27d9f4fc61865396087e8f61fb5d4e8b4afcfe6d
[idea/community.git] / platform / analysis-impl / src / com / intellij / codeInspection / ex / InspectionToolRegistrar.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.intellij.codeInspection.ex;
18
19 import com.intellij.codeInspection.*;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.components.ServiceManager;
22 import com.intellij.openapi.diagnostic.Logger;
23 import com.intellij.openapi.extensions.Extensions;
24 import com.intellij.openapi.progress.ProgressManager;
25 import com.intellij.openapi.util.Factory;
26 import com.intellij.util.containers.ContainerUtil;
27 import gnu.trove.THashSet;
28 import org.jetbrains.annotations.NotNull;
29
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.Set;
33
34 /**
35  * @author max
36  */
37 public class InspectionToolRegistrar {
38   private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.ex.InspectionToolRegistrar");
39
40   private final List<Factory<InspectionToolWrapper>> myInspectionToolFactories = new ArrayList<Factory<InspectionToolWrapper>>();
41
42   private boolean myInspectionComponentsLoaded = false;
43
44   private synchronized void ensureInitialized() {
45     if (!myInspectionComponentsLoaded) {
46       myInspectionComponentsLoaded = true;
47       Set<InspectionToolProvider> providers = new THashSet<InspectionToolProvider>();
48       ContainerUtil.addAll(providers, ApplicationManager.getApplication().getComponents(InspectionToolProvider.class));
49       ContainerUtil.addAll(providers, Extensions.getExtensions(InspectionToolProvider.EXTENSION_POINT_NAME));
50       registerTools(providers.toArray(new InspectionToolProvider[providers.size()]));
51       for (final LocalInspectionEP ep : Extensions.getExtensions(LocalInspectionEP.LOCAL_INSPECTION)) {
52         myInspectionToolFactories.add(new Factory<InspectionToolWrapper>() {
53           @Override
54           public InspectionToolWrapper create() {
55             return new LocalInspectionToolWrapper(ep);
56           }
57         });
58       }
59       for (final InspectionEP ep : Extensions.getExtensions(InspectionEP.GLOBAL_INSPECTION)) {
60         myInspectionToolFactories.add(new Factory<InspectionToolWrapper>() {
61           @Override
62           public InspectionToolWrapper create() {
63             return new GlobalInspectionToolWrapper(ep);
64           }
65         });
66       }
67       for (InspectionToolsFactory factory : Extensions.getExtensions(InspectionToolsFactory.EXTENSION_POINT_NAME)) {
68         for (final InspectionProfileEntry profileEntry : factory.createTools()) {
69           myInspectionToolFactories.add(new Factory<InspectionToolWrapper>() {
70             @Override
71             public InspectionToolWrapper create() {
72               return wrapTool(profileEntry);
73             }
74           });
75         }
76       }
77     }
78   }
79
80   @NotNull
81   public static InspectionToolWrapper wrapTool(@NotNull InspectionProfileEntry profileEntry) {
82     if (profileEntry instanceof LocalInspectionTool) {
83       return new LocalInspectionToolWrapper((LocalInspectionTool)profileEntry);
84     }
85     if (profileEntry instanceof GlobalInspectionTool) {
86       return new GlobalInspectionToolWrapper((GlobalInspectionTool)profileEntry);
87     }
88     throw new RuntimeException("unknown inspection class: " + profileEntry + "; "+profileEntry.getClass());
89   }
90
91   private void registerTools(@NotNull InspectionToolProvider[] providers) {
92     for (InspectionToolProvider provider : providers) {
93       Class[] classes = provider.getInspectionClasses();
94       for (Class aClass : classes) {
95         registerInspectionTool(aClass);
96       }
97     }
98   }
99
100   @NotNull
101   private Factory<InspectionToolWrapper> registerInspectionTool(@NotNull final Class aClass) {
102     if (LocalInspectionTool.class.isAssignableFrom(aClass)) {
103       return registerLocalInspection(aClass, true);
104     }
105     if (GlobalInspectionTool.class.isAssignableFrom(aClass)) {
106       return registerGlobalInspection(aClass, true);
107     }
108     throw new RuntimeException("unknown inspection class: " + aClass);
109   }
110
111   public static InspectionToolRegistrar getInstance() {
112     return ServiceManager.getService(InspectionToolRegistrar.class);
113   }
114
115   /**
116    * make sure that it is not too late
117    */
118   @NotNull
119   private Factory<InspectionToolWrapper> registerInspectionToolFactory(@NotNull Factory<InspectionToolWrapper> factory, boolean store) {
120     if (store) {
121       myInspectionToolFactories.add(factory);
122     }
123     return factory;
124   }
125
126   @NotNull
127   private Factory<InspectionToolWrapper> registerLocalInspection(final Class toolClass, boolean store) {
128     return registerInspectionToolFactory(new Factory<InspectionToolWrapper>() {
129       @Override
130       public InspectionToolWrapper create() {
131         return new LocalInspectionToolWrapper((LocalInspectionTool)InspectionToolsRegistrarCore.instantiateTool(toolClass));
132       }
133     }, store);
134   }
135
136   @NotNull
137   private Factory<InspectionToolWrapper> registerGlobalInspection(@NotNull final Class aClass, boolean store) {
138     return registerInspectionToolFactory(new Factory<InspectionToolWrapper>() {
139       @Override
140       public InspectionToolWrapper create() {
141         return new GlobalInspectionToolWrapper((GlobalInspectionTool) InspectionToolsRegistrarCore.instantiateTool(aClass));
142       }
143     }, store);
144   }
145
146   @NotNull
147   public List<InspectionToolWrapper> createTools() {
148     ensureInitialized();
149
150     final List<InspectionToolWrapper> tools = ContainerUtil.newArrayListWithCapacity(myInspectionToolFactories.size());
151     for (final Factory<InspectionToolWrapper> factory : myInspectionToolFactories) {
152       ProgressManager.checkCanceled();
153       final InspectionToolWrapper toolWrapper = factory.create();
154       if (toolWrapper != null && checkTool(toolWrapper) == null) {
155         tools.add(toolWrapper);
156       }
157     }
158
159     return tools;
160   }
161
162   private static String checkTool(@NotNull final InspectionToolWrapper toolWrapper) {
163     if (!(toolWrapper instanceof LocalInspectionToolWrapper)) {
164       return null;
165     }
166     String message = null;
167     try {
168       final String id = ((LocalInspectionToolWrapper)toolWrapper).getID();
169       if (id == null || !LocalInspectionTool.isValidID(id)) {
170         message = InspectionsBundle.message("inspection.disabled.wrong.id", toolWrapper.getShortName(), id, LocalInspectionTool.VALID_ID_PATTERN);
171       }
172     }
173     catch (Throwable t) {
174       message = InspectionsBundle.message("inspection.disabled.error", toolWrapper.getShortName(), t.getMessage());
175     }
176     if (message != null) {
177       LOG.error(message);
178     }
179     return message;
180   }
181 }