/** * Gets the import/require declaration that a string literal belongs to, e.g 'normal' -> * 'const styles = require("./foo.css")' or 'import styles from "./foo.css"' based on <code>styles['normal']</code> * * @param classNameLiteral a string literal that is potentially a CSS class name * @return the JS variable that is a potential require of a style sheet file, or <code>null</code> if the PSI structure doesn't match */ public static PsiElement getCssClassNamesImportOrRequireDeclaration(JSLiteralExpression classNameLiteral) { final JSIndexedPropertyAccessExpression expression = PsiTreeUtil.getParentOfType(classNameLiteral, JSIndexedPropertyAccessExpression.class); if (expression != null) { // string literal is part of "var['string literal']", e.g. "styles['normal']" if (expression.getQualifier() != null) { final PsiReference psiReference = expression.getQualifier().getReference(); if (psiReference != null) { final PsiElement varReference = psiReference.resolve(); if (varReference instanceof JSVariable) { return varReference; } if(varReference instanceof ES6ImportedBinding) { return varReference.getParent(); } } } } return null; }
@Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) { final JSVariable[] vars = getVariables(); for(JSVariable var : vars) { if(lastParent != null && lastParent.getParent() == var) { break; } if(!processor.execute(var, state)) { return false; } } return true; }
@Override public void delete() throws IncorrectOperationException { final ASTNode myNode = getNode(); final ASTNode parent = myNode.getTreeParent(); if(parent.getElementType() == JSElementTypes.VAR_STATEMENT) { final JSVariable[] jsVariables = ((JSVarStatement) parent.getPsi()).getVariables(); if(jsVariables.length == 1) { parent.getPsi().delete(); } else { JSChangeUtil.removeRangeWithRemovalOfCommas(myNode, parent); } return; } throw new IncorrectOperationException("Cannot delete variable from parent : " + parent.getElementType()); }
@Override public PsiElement getNavigationElement() { PsiElement parent = getParent().getParent(); if(parent instanceof JSClass) { PsiElement parentOriginalElement = parent.getNavigationElement(); if(parentOriginalElement != parent) { JSVariable jsVariable = ((JSClass) parentOriginalElement).findFieldByName(getName()); return jsVariable != null ? jsVariable : this; } } return JSPsiImplUtils.findTopLevelNavigatableElement(this); }
@Override protected String buildFunctionBodyText(final String retType, final JSParameterList parameterList, final JSVariable func) { final String semicolon = codeStyleSettings.USE_SEMICOLON_AFTER_STATEMENT ? ";" : ""; String varName = func.getName(); if(myMode == GenerationMode.SETTERS) { String checkNeedEvent = ""; String dispatchEvent = ""; if(bindableProperties) { String eventName = getEventName(transformVarNameToAccessorName(varName, codeStyleSettings)); dispatchEvent = "\ndispatchEvent(new Event(\"" + eventName + "\"))" + semicolon; checkNeedEvent = "if(" + varName + "==" + PARAMETER_NAME + ") return" + semicolon + "\n"; } return "{\n" + checkNeedEvent + varName + "=" + PARAMETER_NAME + semicolon + dispatchEvent + "\n}"; } else if(myMode == GenerationMode.GETTERS) { return "{\nreturn " + varName + semicolon + "\n}"; } return " {}"; }
@Override public void visitJSFunctionDeclaration(JSFunction function) { super.visitJSFunctionDeclaration(function); final JSParameterList parameterList = function.getParameterList(); if (parameterList == null) { return; } final JSParameter[] parameters = parameterList.getParameters(); for (JSVariable variable : parameters) { final String name = variable.getName(); if (name == null) { continue; } if (isValid(name)) { continue; } registerVariableError(variable); } }
private static Iterable<PsiElement> getReferences(@NotNull final JSVariable variable, @Nullable final PsiElement scope, final int minTextOffset, final int maxTextOffset) { final PsiElement iteratedScope; if (scope == null) { JSElement function = PsiTreeUtil.getParentOfType(variable, JSFunction.class); iteratedScope = ((function == null) ? FindReferenceUtil.getFarthestAncestor(variable, XmlFile.class) : function); } else { iteratedScope = scope; } return new Iterable<PsiElement>() { @Override public Iterator<PsiElement> iterator() { return new JSReferenceIterator(variable, minTextOffset, maxTextOffset, iteratedScope); } }; }
protected @Nullable String getVariableName() { if (origPsiElement.getParent() instanceof ES6ImportedBinding) { this.isES6Import = true; return getImportVarName(origPsiElement); } JSVariable var = this.getVariable(); return var != null ? var.getName() : null; }
@RequiredReadAction @Override public JSVariableStub createStub(@NotNull JSVariable psi, StubElement parentStub) { String name = psi.getName(); int flags = JSVariableStubImpl.buildFlags(psi); String typeString = psi.getTypeString(); String initializerText = psi.getInitializerText(); String qualifiedName = psi.getQualifiedName(); return new JSVariableStubImpl(name, flags, typeString, initializerText, qualifiedName, parentStub, this); }
private @NotNull Map<String, JSVariable> initFields() { Map<String, JSVariable> name2FieldsMap = myName2FieldsMap; if(name2FieldsMap == null) { synchronized(this) { name2FieldsMap = myName2FieldsMap; if(name2FieldsMap == null) { name2FieldsMap = new THashMap<String, JSVariable>(); for(JSVariable variable : getFields()) { final String name = variable.getName(); if(name != null) { name2FieldsMap.put(name, variable); } } myName2FieldsMap = name2FieldsMap; } } } return name2FieldsMap; }
@Override public void delete() throws IncorrectOperationException { final PsiElement parent = getParent(); if(parent instanceof JSAssignmentExpression) { final PsiElement grandParent = parent.getParent(); if(grandParent instanceof JSStatement) { grandParent.delete(); return; } else if(grandParent instanceof JSBinaryExpression) { ((JSBinaryExpression) grandParent).getROperand().replace(((JSAssignmentExpression) parent).getROperand()); return; } else if(grandParent instanceof JSVariable) { final JSExpression initializerExpression = ((JSVariable) grandParent).getInitializer(); initializerExpression.replace(((JSAssignmentExpression) parent).getROperand()); return; } } super.delete(); }
@Override protected String buildFunctionAttrText(final String attrText, final JSAttributeList attributeList, final JSVariable function) { String baseText = "public" + (attributeList != null && attributeList.hasModifier(JSAttributeList.ModifierType.STATIC) ? " static" : ""); if(bindableProperties && myMode == GenerationMode.GETTERS) { baseText = "[Bindable(event=\"" + getEventName(transformVarNameToAccessorName(function.getName(), codeStyleSettings)) + "\")]\n" + baseText; } return baseText; }
@Override protected String buildFunctionKind(final JSVariable fun) { if(myMode == GenerationMode.GETTERS) { return "get "; } if(myMode == GenerationMode.SETTERS) { return "set "; } return super.buildFunctionKind(fun); }
@Override protected String buildParameterList(final JSParameterList parameterList, final JSVariable fun) { if(myMode == GenerationMode.SETTERS) { final String s = fun.getTypeString(); return "(" + PARAMETER_NAME + (s != null ? ":" + s : "") + ")"; } return (parameterList != null ? parameterList.getText() : "()"); }
@Override public boolean isReadWriteAccessible(PsiElement element) { return element instanceof JSVariable || ((element instanceof JSFunction) && (((JSFunction) element).isGetProperty() || ((JSFunction) element).isSetProperty())) || element instanceof JSDefinitionExpression; }
@Override public boolean isSafeDeleteAvailable(PsiElement element) { boolean simpleElement = element instanceof JSFunction || element instanceof JSVariable || element instanceof JSDefinitionExpression || element instanceof JSProperty || element instanceof JSClass; return simpleElement && ((JSNamedElement) element).getName() != null; }
@Override public void visitJSVarStatement(JSVarStatement jsVarStatement) { super.visitJSVarStatement(jsVarStatement); final JSVariable[] variables = jsVarStatement.getVariables(); for (JSVariable variable : variables) { final String name = variable.getName(); if (name == null) { continue; } if (isValid(name)) { continue; } registerVariableError(variable); } }
public static JSReferenceExpression[] findReferences(@NotNull JSVariable variable) { final JSReferenceVisitor visitor = new JSReferenceVisitor(variable, Integer.MAX_VALUE, 0, Integer.MAX_VALUE); JSElement scope = PsiTreeUtil.getParentOfType(variable, JSFunction.class); if (scope == null) { scope = getFarthestAncestor(variable, JSElement.class); } visitor.visitJSElement(scope); return visitor.getReferences(); }
public JSReferenceVisitor(@NotNull JSVariable variable, int maxCount, int minTextOffset, int maxTextOffset) { this.variable = variable; this.variableName = variable.getName(); this.maxCount = maxCount; this.minTextOffset = minTextOffset; this.maxTextOffset = maxTextOffset; this.references = new ArrayList<JSReferenceExpression>(); }
@Override public void visitJSReferenceExpression(final JSReferenceExpression expression) { super.visitJSReferenceExpression(expression); if (expression.getText().equals(this.variableName)) { final JSVariable referent = ControlFlowUtils.resolveVariable(expression); if (referent != null && this.variable.equals(referent)) { this.references.add(expression); } } }
public JSReferenceIterator(@NotNull JSVariable variable, int minTextOffset, int maxTextOffset, @NotNull PsiElement element) { super(element, false, minTextOffset, maxTextOffset); this.variable = variable; this.variableName = variable.getName(); }
@Override public boolean visitElement(PsiElement element) { if (!(element.getText().equals(this.variableName) && element instanceof JSReferenceExpression)) { return false; } final JSVariable referent = ControlFlowUtils.resolveVariable((JSReferenceExpression) element); return (referent != null && this.variable.equals(referent)); }
protected static boolean isJSVar (@Nullable PsiElement element) { return element instanceof JSVariable; }
@Override public JSVariable createPsi(@NotNull JSVariableStub stub) { return new JSVariableImpl(stub); }
public static int buildFlags(final JSVariable clazz) { return (clazz.isDeprecated() ? DEPRECATED_MASK : 0) | (clazz.isConst() ? CONST_MASK : clazz.isLocal() ? LOCAL_MASK : 0); }
@Override public JSVariable[] getVariables() { return getStubOrPsiChildren(JSElementTypes.VARIABLE, JSVariable.EMPTY_ARRAY); }
@Override public JSVariable[] getFields() { final JSClassStub classStub = getStub(); final List<JSVariable> vars = new ArrayList<JSVariable>(3); if(classStub != null) { for(JSVarStatement var : getStubChildrenByType(classStub, JSElementTypes.VAR_STATEMENT, new ArrayFactory<JSVarStatement>() { @Override public JSVarStatement[] create(final int count) { return new JSVarStatement[count]; } })) { vars.addAll(Arrays.asList(var.getVariables())); } } else { processDeclarations(new PsiScopeProcessor() { @Override public boolean execute(final PsiElement element, final ResolveState state) { if(element instanceof JSVariable) { vars.add((JSVariable) element); } return true; } @Override public <T> T getHint(final Key<T> hintClass) { return null; } @Override public void handleEvent(final Event event, final Object associated) { } }, ResolveState.initial(), this, this); } return vars.toArray(JSVariable.EMPTY_ARRAY); }
@Override public JSVariable findFieldByName(String name) { return initFields().get(name); }
@Override @NotNull public Collection<Group> group(final AbstractTreeNode parent, final Collection<TreeElement> children) { if(isParentGrouped(parent)) { return Collections.emptyList(); } final Map<String, Group> groups = new THashMap<String, Group>(); for(TreeElement _child : children) { if(!(_child instanceof JSStructureViewElement)) { continue; } JSStructureViewElement child = (JSStructureViewElement) _child; final PsiElement value = child.getValue(); if(value instanceof JSVariable) { if(!child.isInherited()) { continue; } PsiElement parentElement = value.getParent(); if(parentElement instanceof JSVarStatement) { parentElement = parentElement.getParent(); } if(parentElement instanceof JSClass) { addGroup(groups, _child, ((JSClass) parentElement).getQualifiedName()); } } else if(value instanceof JSFunction) { processFunction((JSStructureViewElement) parent.getValue(), groups, _child, value); } } return groups.values(); }
@Override public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { final JSCodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(project).getCustomSettings(JSCodeStyleSettings.class); evalAnchor(editor, file); @NonNls String functionText = "public function " + jsClass.getName() + "("; @NonNls String initialization = ""; boolean first = true; final String semicolon = JSChangeUtil.getSemicolon(project); Set<JSVariable> toProcess = getElementsToProcess(); Iterator<JSVariable> variableIterator = toProcess.iterator(); boolean hadSuperClassConstructorInitializationBefore = false; while(variableIterator.hasNext()) { JSVariable var = variableIterator.next(); if(!first) { functionText += ", "; } first = false; final String name = var.getName(); String parameterName = transformVarNameToAccessorName(name, codeStyleSettings); final String typeString = var.getTypeString(); functionText += parameterName + (typeString != null ? ":" + typeString : ""); if(JSResolveUtil.findParent(var) == jsClass) { if(hadSuperClassConstructorInitializationBefore) { initialization += ")" + semicolon + "\n"; hadSuperClassConstructorInitializationBefore = false; } initialization += (parameterName.equals(name) ? "this." : "") + name + " = " + parameterName + semicolon + "\n"; } else { if(hadSuperClassConstructorInitializationBefore) { initialization += ", "; } else { initialization += "super("; } initialization += parameterName; hadSuperClassConstructorInitializationBefore = true; } } if(hadSuperClassConstructorInitializationBefore) { initialization += ")" + semicolon + "\n"; } functionText += ") {\n"; functionText += initialization; functionText += "}"; doAddOneMethod(project, functionText, anchor); }
@Override public Set<JSVariable> getElementsToProcess() { LinkedHashSet<JSVariable> vars = new LinkedHashSet<JSVariable>(); JSFunction nontrivialSuperClassConstructor = JSAnnotatingVisitor.getNontrivialSuperClassConstructor(jsClass); if(nontrivialSuperClassConstructor != null) { vars.addAll(Arrays.asList(nontrivialSuperClassConstructor.getParameterList().getParameters())); } vars.addAll(super.getElementsToProcess()); return vars; } }; } else if(mode == GenerationMode.TOSTRING) { return new BaseCreateMethodsFix<JSVariable>(jsClass) { @Override public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { evalAnchor(editor, file); final boolean[] needOverride = new boolean[1]; JSResolveUtil.processOverrides(jsClass, new JSResolveUtil.OverrideHandler() { @Override public boolean process(final ResolveProcessor processor, final PsiElement scope, final String className) { needOverride[0] = !"Object".equals(className); return false; } }, "toString", null, myJsClass); @NonNls String functionText = "public " + (needOverride[0] ? "override " : "") + "function toString():String {\nreturn " + (needOverride[0] ? "super.toString() + \"" : "\"" + jsClass.getName()) + "{"; final String semicolon = JSChangeUtil.getSemicolon(project); boolean first = true; for(JSVariable var : getElementsToProcess()) { if(!first) { functionText += " + \","; } first = false; functionText += var.getName() + "=\" + String(" + var.getName() + ")"; } functionText += "+\"}\"" + semicolon + "\n}"; doAddOneMethod(project, functionText, anchor); } }; }
@Override protected void collectCandidates(final JSClass clazz, final Collection<JSNamedElementNode> candidates) { final LinkedHashMap<String, JSNamedElement> candidatesMap = new LinkedHashMap<String, JSNamedElement>(); final JSCodeStyleSettings codeStyleSettings = CodeStyleSettingsManager.getSettings(clazz.getProject()).getCustomSettings(JSCodeStyleSettings .class); final ResolveProcessor processor = new ResolveProcessor(null) { { setToProcessMembers(true); setToProcessHierarchy(false); setLocalResolve(true); } @Override public boolean execute(final PsiElement element, final ResolveState state) { final JSNamedElement namedElement = (JSNamedElement) element; if(!(element instanceof JSVariable)) { if(element instanceof JSFunction) { final JSFunction function = (JSFunction) element; if(mode == GenerationMode.GETTERS && function.isGetProperty() || mode == GenerationMode.SETTERS && function.isSetProperty()) { candidatesMap.put(function.getName(), function); } } return true; } else if(((JSVariable) element).isConst()) { return true; } final String name = namedElement.getName(); final String accessorName = transformVarNameToAccessorName(name, codeStyleSettings); if(/*!name.equals(accessorName) &&*/ !candidatesMap.containsKey(accessorName)) { candidatesMap.put(accessorName, namedElement); } return true; } }; clazz.processDeclarations(processor, ResolveState.initial(), clazz, clazz); for(JSNamedElement n : candidatesMap.values()) { if(n instanceof JSVariable) { candidates.add(new JSNamedElementNode(n)); } } }
@Override protected String buildName(final JSVariable fun) { return transformVarNameToAccessorName(super.buildName(fun), codeStyleSettings); }
@Override public boolean isDeclarationWriteAccess(PsiElement element) { return (element instanceof JSVariable && ((JSVariable) element).getInitializer() != null); }
@Override @NotNull public String getType(@NotNull PsiElement element) { if(element instanceof JSFunction) { return JavaScriptBundle.message("javascript.language.term.function"); } if(element instanceof JSClass) { return JavaScriptBundle.message("javascript.language.term.class"); } if(element instanceof JSNamespaceDeclaration) { return JavaScriptBundle.message("javascript.language.term.namespace"); } if(element instanceof JSParameter) { return JavaScriptBundle.message("javascript.language.term.parameter"); } if(element instanceof JSProperty) { return JavaScriptBundle.message("javascript.language.term.property"); } if(element instanceof JSVariable) { return JavaScriptBundle.message("javascript.language.term.variable"); } if(element instanceof JSLabeledStatement) { return JavaScriptBundle.message("javascript.language.term.label"); } if(element instanceof JSDefinitionExpression) { return JavaScriptBundle.message("javascript.language.term.value"); } if(element instanceof XmlTag) { return JavaScriptBundle.message("javascript.language.term.tag"); } if(element instanceof XmlToken) { return JavaScriptBundle.message("javascript.language.term.attribute.value"); } if(element instanceof JSPackageStatement) { return JavaScriptBundle.message("javascript.language.term.package"); } return ""; }
@Override public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { PsiElement anchor = descriptor.getPsiElement(); PsiFile containingFile = anchor.getContainingFile(); if(!CodeInsightUtilBase.getInstance().prepareFileForWrite(containingFile)) { return; } if(anchor.getParent() instanceof JSFunction) { anchor = ((JSFunction) anchor.getParent()).getParameterList(); } OpenFileDescriptor openDescriptor = new OpenFileDescriptor(project, containingFile.getVirtualFile(), anchor.getTextRange().getEndOffset()); openDescriptor.navigate(true); Editor textEditor = FileEditorManager.getInstance(project).getSelectedTextEditor(); TemplateManager templateManager = TemplateManager.getInstance(project); Template t = templateManager.createTemplate("", ""); t.addTextSegment(":"); boolean hasDetectedTypeFromUsage = false; final PsiElement anchorParent = anchor.getParent(); if(anchorParent instanceof JSVariable) { final JSExpression expression = ((JSVariable) anchorParent).getInitializer(); if(expression != null) { BaseCreateFix.guessExprTypeAndAddSuchVariable(expression, t, "a", containingFile, Collections.singleton(JavaScriptFeature.CLASS)); hasDetectedTypeFromUsage = true; } } if(!hasDetectedTypeFromUsage) { String defaultValue = "uint"; if(ApplicationManager.getApplication().isUnitTestMode()) { t.addTextSegment(defaultValue); } else { t.addVariable("a", new MacroCallNode(MacroFactory.createMacro("complete")), new BaseCreateFix.MyExpression(defaultValue), true); } } templateManager.startTemplate(textEditor, t); }
protected void registerVariableError(JSVariable variable){ final PsiElement nameIdentifier = variable.getFirstChild(); registerError(nameIdentifier); }
public VariableUsedVisitor(@NotNull JSVariable variable) { super(); this.variable = variable; }
VariableUsedInInnerFunctionVisitor(JSVariable variable) { super(); this.variable = variable; }
public static Iterable<PsiElement> getReferences(@NotNull JSVariable variable) { return getReferences(variable, null, 0, Integer.MAX_VALUE); }