/* * Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC * All rights reserved. * * The source code of this document is proprietary work, and is not licensed for * distribution. For information about licensing, contact Sam Harwell at: * sam@tunnelvisionlabs.com */ package org.tvl.goworks.editor.go.semantics; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.logging.Level; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; import org.netbeans.api.annotations.common.NonNull; import org.tvl.goworks.editor.go.codemodel.CodeElementModel; import org.tvl.goworks.editor.go.codemodel.FunctionModel; import org.tvl.goworks.editor.go.codemodel.IntrinsicTypeModels; import org.tvl.goworks.editor.go.codemodel.PackageModel; import org.tvl.goworks.editor.go.codemodel.TypeModel; /** * * @author Sam Harwell */ public class UnqualifiedIdentifierElementReference extends CodeElementReference { @NonNull private final TerminalNode identifier; public UnqualifiedIdentifierElementReference(@NonNull TerminalNode identifier) { this.identifier = identifier; } @Override public Collection<? extends CodeElementModel> resolve(GoAnnotatedParseTree annotatedParseTree, PackageModel currentPackage, Map<String, Collection<PackageModel>> resolvedPackages) { if (identifier != null) { TypeModel intrinsicType = IntrinsicTypeModels.getIntrinsicType(identifier.getText()); if (intrinsicType != null) { return Collections.singletonList(intrinsicType); } Collection<? extends CodeElementModel> result = annotatedParseTree.getTreeDecorator().getProperty(identifier, GoAnnotations.MODELS); if (result != null) { return result; } TerminalNode decl; if (annotatedParseTree.getTreeDecorator().getProperty(identifier, GoAnnotations.EXPLICIT_TYPE) != null) { decl = identifier; } else { decl = annotatedParseTree.getTreeDecorator().getProperty(identifier, GoAnnotations.LOCAL_TARGET); } if (decl != null) { result = annotatedParseTree.getTreeDecorator().getProperty(decl, GoAnnotations.MODELS); if (result != null) { return result; } } if (decl == null || annotatedParseTree.getTreeDecorator().getProperty(decl, GoAnnotations.NODE_TYPE) == NodeType.TYPE_DECL) { result = currentPackage.getMembers(identifier.getSymbol().getText()); Collection<PackageModel> mergePackages = resolvedPackages.get(""); if (mergePackages != null && !mergePackages.isEmpty()) { List<CodeElementModel> combinedResults = new ArrayList<>(result); for (PackageModel otherPackage : mergePackages) { combinedResults.addAll(otherPackage.getMembers(identifier.getSymbol().getText())); } result = combinedResults; } if (decl == null || !result.isEmpty()) { return result; } } NodeType nodeType = annotatedParseTree.getNodeType(identifier); switch (nodeType) { case VAR_REF: { CodeElementReference varType = annotatedParseTree.getTreeDecorator().getProperty(decl, GoAnnotations.EXPR_TYPE); if (varType == CodeElementReference.MISSING) { ParseTree explicitType = annotatedParseTree.getTreeDecorator().getProperty(decl, GoAnnotations.EXPLICIT_TYPE); if (explicitType != null) { varType = annotatedParseTree.getTreeDecorator().getProperty(explicitType, GoAnnotations.CODE_CLASS); if (annotatedParseTree.getTreeDecorator().getProperty(decl, GoAnnotations.VARIADIC)) { varType = new VariadicParameterTypeReference(varType); } } else { ParseTree implicitType = annotatedParseTree.getTreeDecorator().getProperty(decl, GoAnnotations.IMPLICIT_TYPE); if (implicitType == null) { LOGGER.log(Level.FINE, "Unable to find an explicit or implicit type for the tree."); return Collections.emptyList(); } varType = annotatedParseTree.getTreeDecorator().getProperty(implicitType, GoAnnotations.EXPR_TYPE); } if (varType == CodeElementReference.MISSING) { LOGGER.log(Level.FINE, String.format("Unable to resolve the type of var declared with token: '%s'.", decl.toString())); return Collections.emptyList(); } annotatedParseTree.getTreeDecorator().putProperty(decl, GoAnnotations.EXPR_TYPE, varType); } Collection<? extends CodeElementModel> resolved = varType.resolve(annotatedParseTree, currentPackage, resolvedPackages); int implicitIndex = annotatedParseTree.getTreeDecorator().getProperty(decl, GoAnnotations.IMPLICIT_INDEX); if (implicitIndex >= 0) { Collection<CodeElementModel> unwrapped = new ArrayList<>(); for (CodeElementModel model : resolved) { if (model instanceof BundledReturnTypeModel) { BundledReturnTypeModel bundled = (BundledReturnTypeModel)model; if (bundled.getReturnValues().size() > implicitIndex) { unwrapped.add(bundled.getReturnValues().get(implicitIndex)); } } else if (implicitIndex == 0) { unwrapped.add(model); } } resolved = unwrapped; } return resolved; } case FUNC_REF: { ArrayList<CodeElementModel> resolved = new ArrayList<>(); resolved.addAll(currentPackage.getFunctions(identifier.getSymbol().getText())); Collection<? extends PackageModel> mergedImports = resolvedPackages.get(""); if (mergedImports != null) { for (PackageModel model : mergedImports) { resolved.addAll(model.getFunctions(identifier.getSymbol().getText())); } } for (int i = resolved.size() - 1; i >= 0; i--) { CodeElementModel element = resolved.get(i); if (element instanceof FunctionModel && ((FunctionModel)element).isMethod()) { resolved.remove(i); } } return resolved; } case TYPE_REF: throw new UnsupportedOperationException("Not supported yet."); default: throw new UnsupportedOperationException("Not supported yet."); } } return Collections.emptyList(); } }