Skip to content
This repository has been archived by the owner on May 27, 2020. It is now read-only.

Commit

Permalink
Added check for bracket notation & duplicate goog.require/provide sta…
Browse files Browse the repository at this point in the history
…tements (v. 1.1.0). Closes #5
  • Loading branch information
Dan1ve committed Jul 1, 2018
1 parent ece564b commit 826ebac
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 131 deletions.
Binary file modified closure-inspections-plugin.jar
Binary file not shown.
10 changes: 6 additions & 4 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
<idea-plugin>
<id>de.veihelmann.closureplugin</id>
<name>Inspections for Google™ Closure</name>
<version>1.0.2</version>
<version>1.1.0</version>
<vendor email="[email protected]">Daniel Veihelmann</vendor>

<description><![CDATA[
This plugin enhances IntelliJ's support for Google Closure. It can determine missing or obsolete 'goog.require'
statements and offers corresponding quick-fixes.
This plugin enhances IntelliJ's support for Google Closure. It can determine missing/obsolete/duplicate 'goog.require'
statements and offers corresponding quick-fixes. In addition, there is an inspection and quick-fix for usages of bracket notation (instead of dot notation) for accessing properties.
More info & source code: https://github.com/Dan1ve/ClosureInspectionsPlugin
]]></description>

<change-notes><![CDATA[
Small bugfixes
- New inspection to avoid bracket notation (e.g. myVar['myField']), which cannot be type-checked by the Closure compiler.
- Duplicate goog.require/goog.provide statements are now reported, too.
]]>
</change-notes>

Expand All @@ -26,6 +27,7 @@
<inspectionToolProvider id="closureinspectionsprovider"
implementation="de.veihelmann.closureplugin.ClosureInspectionsProvider"
order="LAST"/>

</extensions>

<actions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ public class ClosureDependenciesExtractor {
*/
public final Set<String> rawTypesInComments = new HashSet<>();

private final GoogRequireOrProvideRecognizer googRequireOrProvideRecognizer = new GoogRequireOrProvideRecognizer(googRequires, googProvides);

private final List<DependencyRecognizerBase> dependencyRecognizers = asList( //
new GoogRequireOrProvideRecognizer(googRequires, googProvides), //
googRequireOrProvideRecognizer, //
new GoogInheritsLikeDependencyRecognizer(dependencies), //
new ConstructorDependencyRecognizer(dependencies), //
new ES6BaseClassDependencyRecognizer(dependencies), //
Expand All @@ -68,6 +70,15 @@ public void extractDependencies(PsiFile file) {
new RecursiveElementVisitor().visitElement(file);
}

public ListMap<String, PsiElement> getDuplicateGoogRequires() {
return googRequireOrProvideRecognizer.duplicateGoogRequires;
}


public ListMap<String, PsiElement> getDuplicateGoogProvides() {
return googRequireOrProvideRecognizer.duplicateGoogProvides;
}

class RecursiveElementVisitor extends FilteringPsiRecursiveElementWalkingVisitor {

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
public class ClosureInspectionsProvider implements InspectionToolProvider {
@NotNull
public Class[] getInspectionClasses() {
return new Class[]{MissingOrObsoleteGoogRequiresInspection.class,

// TODO: Disabled (for now):
// ConvertToES6ClassInspection.class
return new Class[]{MissingOrObsoleteGoogRequiresInspection.class, UseOfBracketNotationInspection.class
};
}
}
111 changes: 0 additions & 111 deletions src/de/veihelmann/closureplugin/ConvertToES6ClassInspection.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import de.veihelmann.closureplugin.fixes.MissingGoogRequireFix;
import de.veihelmann.closureplugin.fixes.ObsoleteRequireFix;
import de.veihelmann.closureplugin.fixes.ObsoleteRequireOrProvideFix;
import de.veihelmann.closureplugin.utils.ListMap;
import org.jetbrains.annotations.NotNull;

import java.util.List;
Expand Down Expand Up @@ -64,6 +65,9 @@ public void visitFile(PsiFile file) {

markMissingRequires(extractor);
markObsoleteRequires(extractor);

markDuplicationProblem(extractor.getDuplicateGoogRequires(), "Duplicate goog.require");
markDuplicationProblem(extractor.getDuplicateGoogProvides(), "Duplicate goog.provide");
}

private void markObsoleteRequires(ClosureDependenciesExtractor extractor) {
Expand All @@ -78,7 +82,7 @@ private void markObsoleteRequires(ClosureDependenciesExtractor extractor) {
continue;
}
PsiElement requireElement = declaredDependency.getValue();
ObsoleteRequireFix fix = new ObsoleteRequireFix(requireElement);
ObsoleteRequireOrProvideFix fix = new ObsoleteRequireOrProvideFix(requireElement);
problemsHolder.registerProblem(requireElement, "Obsolete require: " + declaredDependency.getKey(), fix);
}
}
Expand All @@ -105,7 +109,12 @@ private boolean namespaceIsPrefixOfProvidedNamespace(Set<String> providedNamespa
return providedNamespaces.stream().anyMatch(providedNamespace -> providedNamespace.startsWith(namespace));
}

}

private void markDuplicationProblem(ListMap<String, PsiElement> duplicateElements, String message) {
duplicateElements.keys().forEach(namespace -> {
duplicateElements.getNullSafe(namespace).forEach(element -> problemsHolder.registerProblem(element, message, new ObsoleteRequireOrProvideFix(element)));
});
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package de.veihelmann.closureplugin;

import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.lang.javascript.psi.JSIndexedPropertyAccessExpression;
import com.intellij.lang.javascript.psi.JSLiteralExpression;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
import de.veihelmann.closureplugin.fixes.BracketNotationFix;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;

/**
* Checks for usages of bracket notation (e.g. myVar['fieldName']), which cannot be type-checked by the Closure compiler.
* Quick fix is to use dot notation (myVar.fieldName) instead.
*/
public class UseOfBracketNotationInspection extends LocalInspectionTool {

@NotNull
@Override
public String getShortName() {
return "UseOfBracketNotationInspection";
}

@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new PsiElementVisitor() {
@Override
public void visitElement(PsiElement element) {
super.visitElement(element);

if (element instanceof JSIndexedPropertyAccessExpression) {
checkBracketNotation((JSIndexedPropertyAccessExpression) element, holder);
}
}
};
}

@NotNull
public String getDisplayName() {
return "Checks for uses of bracket notation";
}

@NotNull
public String getGroupDisplayName() {
return GroupNames.PROPERTIES_GROUP_NAME;
}

public boolean isEnabledByDefault() {
return true;
}

private void checkBracketNotation(JSIndexedPropertyAccessExpression accessElement, ProblemsHolder problemsHolder) {
JSLiteralExpression literal = (JSLiteralExpression) Arrays.stream(accessElement.getChildren()).filter(element -> element instanceof JSLiteralExpression).findFirst().orElse(null);
if (literal != null && literal.getText().matches("[\"']\\w+['\"]")) {
problemsHolder.registerProblem(accessElement, "Access of property " + literal.getText() + " cannot be type-checked (bracket notation)", new BracketNotationFix(literal));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.intellij.lang.javascript.psi.JSReferenceExpression;
import com.intellij.lang.javascript.psi.JSStatement;
import com.intellij.psi.PsiElement;
import de.veihelmann.closureplugin.utils.ListMap;
import org.jetbrains.annotations.NotNull;

import java.util.Map;
Expand All @@ -13,8 +14,12 @@ public class GoogRequireOrProvideRecognizer extends DependencyRecognizerBase<JSC

private final Map<String, PsiElement> googRequires;

public final ListMap<String, PsiElement> duplicateGoogRequires = new ListMap<>();

private final Map<String, JSStatement> googProvides;

public final ListMap<String, PsiElement> duplicateGoogProvides = new ListMap<>();

public GoogRequireOrProvideRecognizer(Map<String, PsiElement> googRequires, Map<String, JSStatement> googProvides) {
this.googRequires = googRequires;
this.googProvides = googProvides;
Expand Down Expand Up @@ -46,14 +51,26 @@ protected boolean doConsumeElement(JSCallExpression callElement) {
}

String targetNamespace = argumentList.getArguments()[0].getText().replaceAll("[\"']", "");
collectGoogRequireOrProvide(callElement, isGoogRequire, targetNamespace);
return true;

}

private void collectGoogRequireOrProvide(JSCallExpression callElement, boolean isGoogRequire, String targetNamespace) {
if (isGoogRequire) {
googRequires.put(targetNamespace, getParentStatement(callElement));
if (googRequires.containsKey(targetNamespace)) {
duplicateGoogRequires.put(targetNamespace, getParentStatement(callElement));
} else {
googRequires.put(targetNamespace, getParentStatement(callElement));
}
} else {
// We checked for goog.provide above, so we are safe in the 'else' clause here.
googProvides.put(targetNamespace, getParentStatement(callElement));
if (googProvides.containsKey(targetNamespace)) {
duplicateGoogProvides.put(targetNamespace, getParentStatement(callElement));
} else {
googProvides.put(targetNamespace, getParentStatement(callElement));
}
}
return true;

}

private @NotNull
Expand Down
Loading

0 comments on commit 826ebac

Please sign in to comment.