Skip to content

Commit

Permalink
Merge pull request #31042 from malinthar/fix-#30832
Browse files Browse the repository at this point in the history
Refactor Hoverutil to filter private class fields and methods
  • Loading branch information
nadeeshaan authored Jun 9, 2021
2 parents c0861c1 + c6cc18d commit c4b3049
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@
*/
package org.ballerinalang.langserver.hover;

import io.ballerina.compiler.api.ModuleID;
import io.ballerina.compiler.api.SemanticModel;
import io.ballerina.compiler.api.symbols.ClassFieldSymbol;
import io.ballerina.compiler.api.symbols.ClassSymbol;
import io.ballerina.compiler.api.symbols.Documentable;
import io.ballerina.compiler.api.symbols.Documentation;
import io.ballerina.compiler.api.symbols.FunctionSymbol;
import io.ballerina.compiler.api.symbols.MethodSymbol;
import io.ballerina.compiler.api.symbols.ModuleSymbol;
import io.ballerina.compiler.api.symbols.ObjectFieldSymbol;
import io.ballerina.compiler.api.symbols.ObjectTypeSymbol;
import io.ballerina.compiler.api.symbols.ParameterSymbol;
import io.ballerina.compiler.api.symbols.Qualifier;
import io.ballerina.compiler.api.symbols.RecordTypeSymbol;
import io.ballerina.compiler.api.symbols.ResourceMethodSymbol;
import io.ballerina.compiler.api.symbols.Symbol;
Expand All @@ -31,6 +36,10 @@
import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol;
import io.ballerina.compiler.api.symbols.TypeSymbol;
import io.ballerina.projects.Document;
import io.ballerina.projects.Module;
import io.ballerina.projects.ModuleId;
import io.ballerina.projects.Package;
import io.ballerina.projects.Project;
import io.ballerina.tools.text.LinePosition;
import org.ballerinalang.langserver.common.constants.ContextConstants;
import org.ballerinalang.langserver.common.utils.CommonUtil;
Expand Down Expand Up @@ -113,37 +122,50 @@ private static Hover getObjectHoverMarkupContent(Documentation documentation, Ob
hoverContent.add(documentation.description().get());
}

Map<String, String> paramsMap = documentation.parameterMap();
if (!paramsMap.isEmpty()) {
List<String> params = new ArrayList<>();
params.add(header(3, ContextConstants.FIELD_TITLE) + CommonUtil.MD_LINE_SEPARATOR);

params.addAll(classSymbol.fieldDescriptors().entrySet().stream()
.map(fieldEntry -> {
String desc = paramsMap.get(fieldEntry.getKey());
String modifiedTypeName =
CommonUtil.getModifiedTypeName(context, fieldEntry.getValue().typeDescriptor());
return quotedString(modifiedTypeName) + " " + italicString(boldString(fieldEntry.getKey()))
+ " : " + desc;
}).collect(Collectors.toList()));
Optional<Package> currentPackage = context.workspace()
.project(context.filePath()).map(Project::currentPackage);
Optional<Module> currentModule = context.currentModule();

if (currentModule.isPresent() && currentPackage.isPresent()) {
Map<String, String> paramsMap = documentation.parameterMap();
if (!paramsMap.isEmpty()) {
List<String> params = new ArrayList<>();
params.add(header(3, ContextConstants.FIELD_TITLE) + CommonUtil.MD_LINE_SEPARATOR);

params.addAll(classSymbol.fieldDescriptors().entrySet().stream()
.filter(fieldEntry -> withValidAccessModifiers(
fieldEntry.getValue(), currentPackage.get(), currentModule.get().moduleId(), context))
.map(fieldEntry -> {
String desc = paramsMap.get(fieldEntry.getKey());
String modifiedTypeName =
CommonUtil.getModifiedTypeName(context, fieldEntry.getValue().typeDescriptor());
return quotedString(modifiedTypeName) + " " + italicString(boldString(fieldEntry.getKey()))
+ " : " + desc;
}).collect(Collectors.toList()));
if (params.size() > 1) {
hoverContent.add(String.join(CommonUtil.MD_LINE_SEPARATOR, params));
}
}

hoverContent.add(String.join(CommonUtil.MD_LINE_SEPARATOR, params));
}
List<String> methods = new ArrayList<>();
classSymbol.methods().entrySet().stream()
.filter(methodSymbol -> withValidAccessModifiers(methodSymbol.getValue(),
currentPackage.get(), currentModule.get().moduleId(), context))
.collect(Collectors.toList()).forEach(methodEntry -> {
StringBuilder methodInfo = new StringBuilder();
Optional<Documentation> methodDoc = methodEntry.getValue().documentation();
methodInfo.append(quotedString(CommonUtil.getModifiedTypeName(context,
methodEntry.getValue().typeDescriptor())));
if (methodDoc.isPresent() && methodDoc.get().description().isPresent()) {
methodInfo.append(CommonUtil.MD_LINE_SEPARATOR).append(methodDoc.get().description().get());
}
methods.add(bulletItem(methodInfo.toString()));
});

List<String> methods = new ArrayList<>();
classSymbol.methods().forEach((name, method) -> {
StringBuilder methodInfo = new StringBuilder();
Optional<Documentation> methodDoc = method.documentation();
methodInfo.append(quotedString(CommonUtil.getModifiedTypeName(context, method.typeDescriptor())));
if (methodDoc.isPresent() && methodDoc.get().description().isPresent()) {
methodInfo.append(CommonUtil.MD_LINE_SEPARATOR).append(methodDoc.get().description().get());
if (!methods.isEmpty()) {
methods.add(0, header(3, ContextConstants.METHOD_TITLE) + CommonUtil.MD_LINE_SEPARATOR);
hoverContent.add(String.join(CommonUtil.MD_LINE_SEPARATOR, methods));
}
methods.add(bulletItem(methodInfo.toString()));
});

if (!methods.isEmpty()) {
methods.add(0, header(3, ContextConstants.METHOD_TITLE) + CommonUtil.MD_LINE_SEPARATOR);
hoverContent.add(String.join(CommonUtil.MD_LINE_SEPARATOR, methods));
}

Hover hover = new Hover();
Expand Down Expand Up @@ -352,4 +374,53 @@ private static String bulletItem(String value) {
private static String header(int level, String header) {
return String.join("", Collections.nCopies(level, "#")) + " " + header;
}

/**
* Check if a given symbol has valid access modifiers to be visible with in the give context.
*
* @param symbol Symbol.
* @param currentPackage Current Package.
* @param currentModule Current Module.
* @return {@link Boolean} Whether the symbol is visible in the current context.
*/
private static Boolean withValidAccessModifiers(Symbol symbol, Package currentPackage,
ModuleId currentModule, HoverContext context) {
Optional<Project> project = context.workspace().project(context.filePath());
Optional<ModuleSymbol> typeSymbolModule = symbol.getModule();

if (project.isEmpty() || typeSymbolModule.isEmpty()) {
return false;
}

boolean isResource = false;
boolean isPrivate = false;
boolean isPublic = false;
boolean isRemote = false;

switch (symbol.kind()) {
case CLASS_FIELD:
isPublic = ((ClassFieldSymbol) symbol).qualifiers().contains(Qualifier.PUBLIC);
isPrivate = ((ClassFieldSymbol) symbol).qualifiers().contains(Qualifier.PRIVATE);
break;
case OBJECT_FIELD:
isPublic = ((ObjectFieldSymbol) symbol).qualifiers().contains(Qualifier.PUBLIC);
isPrivate = ((ObjectFieldSymbol) symbol).qualifiers().contains(Qualifier.PRIVATE);
break;
case RESOURCE_METHOD:
isResource = true;
break;
case METHOD:
isPublic = ((MethodSymbol) symbol).qualifiers().contains(Qualifier.PUBLIC);
isPrivate = ((MethodSymbol) symbol).qualifiers().contains(Qualifier.PRIVATE);
isRemote = ((MethodSymbol) symbol).qualifiers().contains(Qualifier.REMOTE);
}

if (isResource || isRemote || isPublic) {
return true;
}

ModuleID objModuleId = typeSymbolModule.get().id();
return (!isPrivate && objModuleId.moduleName().equals(currentModule.moduleName())
&& objModuleId.orgName().equals(currentPackage.packageOrg().value()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"source": {
"file": "projectls/defmodsource3.bal"
},
"position": {
"line": 2,
"character": 33
},
"expected": {
"result": {
"contents": {
"kind": "markdown",
"value": "Mod3\n \n \n--- \n \n### Fields \n \n`string` ***PERSON_KW*** : PERSON Keyword \n \n--- \n \n### Methods \n \n+ `function () returns string` \nGet name of the person \n"
}
},
"id": {
"left": "324"
},
"jsonrpc": "2.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import projectls.lsmod3;

function myFunction(lsmod3:Mod3Class obj1) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,36 @@ public function mod3Function1() {
public type Mod3Record1 record {
int field1;
module1:TestRecord1 field2;
};
};

# Mod3
#
# + name - Name
# + age - Age
# + PERSON_KW - PERSON Keyword
public class Mod3Class {
private string name;
private int age;
public final string PERSON_KW = "PERSON";

function init(string name, int age) {
self.name = name;
self.age = age;
}

# Get name of the person
# + return - String
public function getName() returns string{
return self.name;
}

# Get name of the person
# + return - String
function getName2() returns string{
return self.name;
}

private function incrementAge() {
self.age += 1;
}
}

0 comments on commit c4b3049

Please sign in to comment.