Skip to content

Commit

Permalink
Merge pull request #41970 from poorna2152/xmlns_decl_order
Browse files Browse the repository at this point in the history
Fix order dependance on `module-xmlns-decl` access
  • Loading branch information
MaryamZi authored Apr 3, 2024
2 parents 4dc1323 + 4190af4 commit f421aaa
Show file tree
Hide file tree
Showing 20 changed files with 319 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -655,16 +655,21 @@ public BLangNode transform(ModulePartNode modulePart) {
compilationUnit.name = currentCompUnitName;
compilationUnit.setPackageID(packageID);
Location pos = getPosition(modulePart);
BLangIdentifier compUnit = this.createIdentifier(pos, compilationUnit.getName());
// Generate import declarations
for (ImportDeclarationNode importDecl : modulePart.imports()) {
BLangImportPackage bLangImport = (BLangImportPackage) importDecl.apply(this);
bLangImport.compUnit = this.createIdentifier(pos, compilationUnit.getName());
bLangImport.compUnit = compUnit;
compilationUnit.addTopLevelNode(bLangImport);
}

// Generate other module-level declarations
for (ModuleMemberDeclarationNode member : modulePart.members()) {
compilationUnit.addTopLevelNode((TopLevelNode) member.apply(this));
TopLevelNode node = (TopLevelNode) member.apply(this);
if (member.kind() == SyntaxKind.MODULE_XML_NAMESPACE_DECLARATION) {
((BLangXMLNS) node).compUnit = compUnit;
}
compilationUnit.addTopLevelNode(node);
}

Location newLocation = new BLangDiagnosticLocation(pos.lineRange().fileName(), 0, 0, 0, 0, 0, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ public void visit(BLangXMLNS source) {
source.cloneRef = clone;
clone.namespaceURI = clone(source.namespaceURI);
clone.prefix = source.prefix;
clone.compUnit = source.compUnit;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
import org.wso2.ballerinalang.compiler.tree.BLangPackage;
import org.wso2.ballerinalang.compiler.tree.SimpleBLangNodeAnalyzer;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangBinaryExpr;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangConstant;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangListConstructorExpr;
Expand Down Expand Up @@ -315,7 +314,8 @@ public void visit(BLangSimpleVarRef varRefExpr, AnalyzerData data) {
dlog.error(varRefExpr.pos, DiagnosticErrorCode.UNDEFINED_MODULE, varRefExpr.pkgAlias);
} else {
BSymbol symbol =
getSymbolOfVarRef(varRefExpr.pos, data.env, names.fromIdNode(varRefExpr.pkgAlias), varName, data);
typeResolver.getSymbolOfVarRef(varRefExpr.pos, data.env, names.fromIdNode(varRefExpr.pkgAlias),
varName);

if (symbol == symTable.notFoundSymbol) {
data.resultType = symTable.semanticError;
Expand Down Expand Up @@ -376,7 +376,8 @@ public void visit(BLangRecordLiteral.BLangRecordVarNameField varRefExpr, Analyze

if (varRefExpr.pkgSymbol != symTable.notFoundSymbol) {
BSymbol symbol =
getSymbolOfVarRef(varRefExpr.pos, data.env, names.fromIdNode(varRefExpr.pkgAlias), varName, data);
typeResolver.getSymbolOfVarRef(varRefExpr.pos, data.env, names.fromIdNode(varRefExpr.pkgAlias),
varName);

if (symbol == symTable.notFoundSymbol) {
data.resultType = symTable.semanticError;
Expand Down Expand Up @@ -2017,24 +2018,6 @@ private BUnionType createFiniteType(BConstantSymbol constantSymbol, Object value
return BUnionType.create(null, memberTypes);
}

private BSymbol getSymbolOfVarRef(Location pos, SymbolEnv env, Name pkgAlias, Name varName, AnalyzerData data) {
if (pkgAlias == Names.EMPTY && data.modTable.containsKey(varName.value)) {
// modTable contains the available constants in current module.
BLangNode node = data.modTable.get(varName.value);
if (node.getKind() == NodeKind.CONSTANT) {
if (!typeResolver.resolvedConstants.contains((BLangConstant) node)) {
typeResolver.resolveConstant(data.env, data.modTable, (BLangConstant) node);
}
} else {
dlog.error(pos, DiagnosticErrorCode.EXPRESSION_IS_NOT_A_CONSTANT_EXPRESSION);
return symTable.notFoundSymbol;
}
}

// Search and get the referenced variable from different module.
return symResolver.lookupMainSpaceSymbolInPackage(pos, env, pkgAlias, varName);
}

private boolean addFields(LinkedHashMap<String, BField> fields, BType keyValueType, String key, Location pos,
BRecordTypeSymbol recordSymbol) {
Name fieldName = Names.fromString(key);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,8 @@ public void visit(BLangXMLNS xmlnsNode, AnalyzerData data) {

typeChecker.checkExpr(xmlnsNode.namespaceURI, currentEnv, symTable.stringType, data.prevEnvs,
data.commonAnalyzerData);
// Namespace node already having the symbol means we are inside an init-function,
// and the symbol has already been declared by the original statement.
if (xmlnsNode.symbol == null) {
// For module-level XML namespace declarations the symbol is already defined at symbol enter.
if (currentEnv.node.getKind() != NodeKind.PACKAGE) {
symbolEnter.defineNode(xmlnsNode, currentEnv);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
import org.wso2.ballerinalang.compiler.tree.BLangAnnotationAttachment;
import org.wso2.ballerinalang.compiler.tree.BLangClassDefinition;
import org.wso2.ballerinalang.compiler.tree.BLangCompilationUnit;
import org.wso2.ballerinalang.compiler.tree.BLangConstantValue;
import org.wso2.ballerinalang.compiler.tree.BLangErrorVariable;
import org.wso2.ballerinalang.compiler.tree.BLangFunction;
import org.wso2.ballerinalang.compiler.tree.BLangIdentifier;
Expand Down Expand Up @@ -417,37 +418,37 @@ private void defineConstructs(BLangPackage pkgNode, SymbolEnv pkgEnv) {
// Define type definitions.
this.typePrecedence = 0;

// Treat constants and type definitions in the same manner, since constants can be used as
// types. Also, there can be references between constant and type definitions in both ways.
// Thus visit them according to the precedence.
List<BLangNode> typeAndClassDefs = new ArrayList<>();
pkgNode.constants.forEach(constant -> typeAndClassDefs.add(constant));
pkgNode.typeDefinitions.forEach(typDef -> typeAndClassDefs.add(typDef));
List<BLangClassDefinition> classDefinitions = getClassDefinitions(pkgNode.topLevelNodes);
classDefinitions.forEach(classDefn -> typeAndClassDefs.add(classDefn));
// Treat constants, type definitions and xmlns declarations in the same manner, since constants can be used
// as types and can be referred to in XMLNS declarations. Also, there can be references between constant,
// type definitions and xmlns declarations in both ways. Thus visit them according to the precedence.
List<BLangNode> moduleDefs = new ArrayList<>();
moduleDefs.addAll(pkgNode.constants);
moduleDefs.addAll(pkgNode.typeDefinitions);
moduleDefs.addAll(pkgNode.xmlnsList);
moduleDefs.addAll(getClassDefinitions(pkgNode.topLevelNodes));

this.env = pkgEnv;
typeResolver.defineBTypes(typeAndClassDefs, pkgEnv);
typeResolver.defineBTypes(moduleDefs, pkgEnv);

// Enabled logging errors after type def visit.
// TODO: Do this in a cleaner way
pkgEnv.logErrors = true;

// Sort type definitions with precedence, before defining their members.
pkgNode.typeDefinitions.sort(getTypePrecedenceComparator());
typeAndClassDefs.sort(getTypePrecedenceComparator());
moduleDefs.sort(getTypePrecedenceComparator());

// Define error details.
defineErrorDetails(pkgNode.typeDefinitions, pkgEnv);

// Define type def members (if any)
defineFunctions(typeAndClassDefs, pkgEnv);
defineFunctions(moduleDefs, pkgEnv);

// Intersection type nodes need to look at the member fields of a structure too.
// Once all the fields and members of other types are set revisit intersection type definitions to validate
// them and set the fields and members of the relevant immutable type.
validateIntersectionTypeDefinitions(pkgNode.typeDefinitions, pkgNode.packageID);
defineUndefinedReadOnlyTypes(pkgNode.typeDefinitions, typeAndClassDefs, pkgEnv);
defineUndefinedReadOnlyTypes(pkgNode.typeDefinitions, moduleDefs, pkgEnv);

// Define service and resource nodes.
pkgNode.services.forEach(service -> defineNode(service, pkgEnv));
Expand Down Expand Up @@ -1166,12 +1167,19 @@ public void initPredeclaredModules(Map<Name, BPackageSymbol> predeclaredModules,

@Override
public void visit(BLangXMLNS xmlnsNode) {
defineXMLNS(env, xmlnsNode);
}

public void defineXMLNS(SymbolEnv symEnv, BLangXMLNS xmlnsNode) {
String nsURI = "";
if (xmlnsNode.namespaceURI.getKind() == NodeKind.SIMPLE_VARIABLE_REF) {
BLangSimpleVarRef varRef = (BLangSimpleVarRef) xmlnsNode.namespaceURI;
if (Symbols.isFlagOn(varRef.symbol.flags, Flags.CONSTANT)) {
nsURI = ((BConstantSymbol) varRef.symbol).value.toString();
checkInvalidNameSpaceDeclaration(xmlnsNode.pos, xmlnsNode.prefix, nsURI);
BLangConstantValue constantValue = ((BConstantSymbol) varRef.symbol).value;
if (constantValue != null) {
nsURI = constantValue.toString();
checkInvalidNameSpaceDeclaration(xmlnsNode.pos, xmlnsNode.prefix, nsURI);
}
}
} else {
nsURI = (String) ((BLangLiteral) xmlnsNode.namespaceURI).value;
Expand All @@ -1185,14 +1193,16 @@ public void visit(BLangXMLNS xmlnsNode) {

Name prefix = names.fromIdNode(xmlnsNode.prefix);
Location nsSymbolPos = prefix.value.isEmpty() ? xmlnsNode.pos : xmlnsNode.prefix.pos;
BXMLNSSymbol xmlnsSymbol = Symbols.createXMLNSSymbol(prefix, nsURI, env.enclPkg.symbol.pkgID, env.scope.owner,
nsSymbolPos, getOrigin(prefix));
BLangIdentifier compUnit = xmlnsNode.compUnit;
BXMLNSSymbol xmlnsSymbol =
Symbols.createXMLNSSymbol(prefix, nsURI, symEnv.enclPkg.symbol.pkgID, symEnv.scope.owner, nsSymbolPos,
getOrigin(prefix), compUnit != null ? names.fromIdNode(compUnit) : null);
xmlnsNode.symbol = xmlnsSymbol;

// First check for package-imports with the same alias.
// Here we do not check for owner equality, since package import is always at the package
// level, but the namespace declaration can be at any level.
BSymbol foundSym = symResolver.lookupSymbolInPrefixSpace(env, xmlnsSymbol.name);
BSymbol foundSym = symResolver.lookupSymbolInPrefixSpace(symEnv, xmlnsSymbol.name);
if ((foundSym.tag & SymTag.PACKAGE) != SymTag.PACKAGE) {
foundSym = symTable.notFoundSymbol;
}
Expand Down Expand Up @@ -1546,7 +1556,7 @@ private void checkErrorsOfUserDefinedType(SymbolEnv env, BLangNode unresolvedTyp
public String getTypeOrClassName(BLangNode node) {
if (node.getKind() == NodeKind.TYPE_DEFINITION || node.getKind() == NodeKind.CONSTANT) {
return ((TypeDefinition) node).getName().getValue();
} else {
} else {
return ((BLangClassDefinition) node).getName().getValue();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ public boolean checkForUniqueSymbol(Location pos, SymbolEnv env, BSymbol symbol)
return true;
}

if (symbol.tag == SymTag.XMLNS && isDistinctXMLNSSymbol((BXMLNSSymbol) symbol, (BXMLNSSymbol) foundSym)) {
return true;
}

// if a symbol is found, then check whether it is unique
if (!isDistinctSymbol(pos, symbol, foundSym)) {
return false;
Expand Down Expand Up @@ -471,11 +475,11 @@ public BSymbol resolvePrefixSymbol(SymbolEnv env, Name pkgAlias, Name compUnit)
BSymbol symbol = entry.symbol;
long tag = symbol.tag;

if ((tag & SymTag.XMLNS) == SymTag.XMLNS) {
if (isDistinctXMLNSSymbol(symbol, compUnit)) {
return symbol;
}

if ((tag & SymTag.IMPORT) == SymTag.IMPORT &&
if (!((tag & SymTag.XMLNS) == SymTag.XMLNS) && (tag & SymTag.IMPORT) == SymTag.IMPORT &&
((BPackageSymbol) symbol).compUnit.equals(compUnit)) {
((BPackageSymbol) symbol).isUsed = true;
return symbol;
Expand All @@ -491,6 +495,14 @@ public BSymbol resolvePrefixSymbol(SymbolEnv env, Name pkgAlias, Name compUnit)
return symTable.notFoundSymbol;
}

private boolean isDistinctXMLNSSymbol(BSymbol symbol, Name compUnit) {
if (symbol instanceof BXMLNSSymbol bxmlnsSymbol) {
Name xmlnsCompUnit = bxmlnsSymbol.compUnit;
return xmlnsCompUnit == null || xmlnsCompUnit.equals(compUnit);
}
return false;
}

public BSymbol resolveAnnotation(Location pos, SymbolEnv env, Name pkgAlias, Name annotationName) {
return this.lookupAnnotationSpaceSymbolInPackage(pos, env, pkgAlias, annotationName);
}
Expand Down Expand Up @@ -2646,6 +2658,19 @@ public boolean isReAtomNode(NodeKind kind) {
}
}

private boolean isDistinctXMLNSSymbol(BXMLNSSymbol symbol, BXMLNSSymbol foundSym) {
Name foundSymCompUnit = foundSym.compUnit;
Name symbolCompUnit = symbol.compUnit;
boolean isFoundSymModuleXmlns = foundSymCompUnit != null;
boolean isSymModuleXmlns = symbolCompUnit != null;
if (isFoundSymModuleXmlns && isSymModuleXmlns) {
return !foundSymCompUnit.value.equals(symbolCompUnit.value);
}
// If only one of the symbols have a compUnit then it is a module level xmlns and the symbols are distinct.
// If they both don't have a compUnit then it is a redeclared prefix.
return isFoundSymModuleXmlns || isSymModuleXmlns;
}

/**
* @since 2.0.0
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
import org.wso2.ballerinalang.compiler.tree.BLangTableKeySpecifier;
import org.wso2.ballerinalang.compiler.tree.BLangTypeDefinition;
import org.wso2.ballerinalang.compiler.tree.BLangVariable;
import org.wso2.ballerinalang.compiler.tree.BLangXMLNS;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangBinaryExpr;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangConstant;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression;
Expand Down Expand Up @@ -213,31 +214,37 @@ public static TypeResolver getInstance(CompilerContext context) {
public void defineBTypes(List<BLangNode> moduleDefs, SymbolEnv pkgEnv) {
this.pkgEnv = pkgEnv;
typePrecedence = 0;
for (BLangNode typeAndClassDef : moduleDefs) {
String typeOrClassName = symEnter.getTypeOrClassName(typeAndClassDef);
for (BLangNode moduleDef : moduleDefs) {
if (moduleDef.getKind() == NodeKind.XMLNS) {
continue;
}
String typeOrClassName = symEnter.getTypeOrClassName(moduleDef);
if (!modTable.containsKey(typeOrClassName)) {
modTable.put(typeOrClassName, typeAndClassDef);
modTable.put(typeOrClassName, moduleDef);
}
}

for (BLangNode def : moduleDefs) {
resolvingTypes = new Stack<>();
resolvingModuleDefs = new Stack<>();
if (def.getKind() == NodeKind.CLASS_DEFN) {
intersectionTypeList = new HashMap<>();
extracted(pkgEnv, (BLangClassDefinition) def, 0);
updateEffectiveTypeOfCyclicIntersectionTypes(pkgEnv);
} else if (def.getKind() == NodeKind.CONSTANT) {
resolveConstant(pkgEnv, modTable, (BLangConstant) def);
} else {
BLangTypeDefinition typeDefinition = (BLangTypeDefinition) def;
intersectionTypeList = new HashMap<>();
resolveTypeDefinition(pkgEnv, modTable, typeDefinition, 0);
BType type = typeDefinition.typeNode.getBType();
if (typeDefinition.hasCyclicReference) {
updateIsCyclicFlag(type);
switch (def.getKind()) {
case CLASS_DEFN -> {
intersectionTypeList = new HashMap<>();
extracted(pkgEnv, (BLangClassDefinition) def, 0);
updateEffectiveTypeOfCyclicIntersectionTypes(pkgEnv);
}
case CONSTANT -> resolveConstant(pkgEnv, modTable, (BLangConstant) def);
case XMLNS -> resolveXMLNS(pkgEnv, (BLangXMLNS) def);
default -> {
BLangTypeDefinition typeDefinition = (BLangTypeDefinition) def;
intersectionTypeList = new HashMap<>();
resolveTypeDefinition(pkgEnv, modTable, typeDefinition, 0);
BType type = typeDefinition.typeNode.getBType();
if (typeDefinition.hasCyclicReference) {
updateIsCyclicFlag(type);
}
updateEffectiveTypeOfCyclicIntersectionTypes(pkgEnv);
}
updateEffectiveTypeOfCyclicIntersectionTypes(pkgEnv);
}
resolvingTypes.clear();
resolvingModuleDefs.clear();
Expand Down Expand Up @@ -1979,6 +1986,33 @@ public void resolveConstant(SymbolEnv symEnv, Map<String, BLangNode> modTable, B
checkUniqueness(constant);
}

public void resolveXMLNS(SymbolEnv symEnv, BLangXMLNS xmlnsNode) {
if (xmlnsNode.namespaceURI.getKind() == NodeKind.SIMPLE_VARIABLE_REF) {
BLangSimpleVarRef varRef = (BLangSimpleVarRef) xmlnsNode.namespaceURI;
varRef.symbol = getSymbolOfVarRef(varRef.pos, symEnv, names.fromIdNode(varRef.pkgAlias),
names.fromIdNode(varRef.variableName));
}
symEnter.defineXMLNS(symEnv, xmlnsNode);
}

public BSymbol getSymbolOfVarRef(Location pos, SymbolEnv env, Name pkgAlias, Name varName) {
if (pkgAlias == Names.EMPTY && modTable.containsKey(varName.value)) {
// modTable contains the available constants in current module.
BLangNode node = modTable.get(varName.value);
if (node.getKind() == NodeKind.CONSTANT) {
if (!resolvedConstants.contains((BLangConstant) node)) {
resolveConstant(env, modTable, (BLangConstant) node);
}
} else {
dlog.error(pos, DiagnosticErrorCode.EXPRESSION_IS_NOT_A_CONSTANT_EXPRESSION);
return symTable.notFoundSymbol;
}
}

// Search and get the referenced variable from different module.
return symResolver.lookupMainSpaceSymbolInPackage(pos, env, pkgAlias, varName);
}

private void checkUniqueness(BLangConstant constant) {
if (constant.symbol.kind != SymbolKind.CONSTANT) {
return;
Expand Down
Loading

0 comments on commit f421aaa

Please sign in to comment.