-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
CodingConvention.java
522 lines (457 loc) · 16.7 KB
/
CodingConvention.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
/*
* Copyright 2007 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.base.Preconditions;
import com.google.errorprone.annotations.Immutable;
import com.google.javascript.rhino.FunctionTypeI;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.NominalTypeBuilder;
import com.google.javascript.rhino.ObjectTypeI;
import com.google.javascript.rhino.StaticSourceFile;
import com.google.javascript.rhino.TypeIRegistry;
import com.google.javascript.rhino.jstype.JSType;
import com.google.javascript.rhino.jstype.JSTypeNative;
import com.google.javascript.rhino.jstype.JSTypeRegistry;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* CodingConvention defines a set of hooks to customize the behavior of the
* Compiler for a specific team/company.
*
*/
@Immutable
public interface CodingConvention extends Serializable {
/**
* This checks whether a given variable name, such as a name in all-caps
* should be treated as if it had the @const annotation.
*
* @param variableName potentially constant variable name
* @return {@code true} if the name should be treated as a constant.
*/
public boolean isConstant(String variableName);
/**
* This checks whether a given key of an object literal, such as a
* name in all-caps should be treated as if it had the @const
* annotation.
*/
public boolean isConstantKey(String keyName);
/**
* This checks that a given {@code key} may be used as a key for an enum.
*
* @param key the potential key to an enum
* @return {@code true} if the {@code key} may be used as an enum key,
* {@code false} otherwise
*/
public boolean isValidEnumKey(String key);
/**
* This checks whether a given parameter name should be treated as an
* optional parameter as far as type checking or function call arg count
* checking is concerned. Note that an optional function parameter may be
* declared as a simple type and is automatically converted to a union of the
* declared type and Undefined.
*
* @param parameter The parameter's node.
* @return {@code true} if the parameter should be treated as an optional
* parameter.
*/
public boolean isOptionalParameter(Node parameter);
/**
* This checks whether a given parameter should be treated as a marker
* for a variable argument list function. A VarArgs parameter must be the
* last parameter in a function declaration.
*
* @param parameter The parameter's node.
* @return {@code true} if the parameter should be treated as a variable
* length parameter.
*/
public boolean isVarArgsParameter(Node parameter);
/**
* Used by CheckMissingReturn. When a function call always throws an error,
* it can be the last stm of a block and we don't warn about missing return.
*/
public boolean isFunctionCallThatAlwaysThrows(Node n);
/**
* Checks whether a global variable or function name should be treated as
* exported, or externally referenceable.
*
* @param name A global variable or function name.
* @param local {@code true} if the name is a local variable.
* @return {@code true} if the name should be considered exported.
*/
public boolean isExported(String name, boolean local);
/**
* Should be isExported(name, true) || isExported(name, false);
*/
public boolean isExported(String name);
/**
* Check whether the property name is eligible for renaming.
*
* This method will not block removal or collapsing
* of the property; it will just block renaming if the
* property is not optimized away.
*
* @param name A property name.
* @return {@code true} if the name can not be renamed.
*/
public boolean blockRenamingForProperty(String name);
/**
* @return the package name for the given source file, or null if
* no package name is known.
*/
public String getPackageName(StaticSourceFile source);
/**
* Checks whether a name should be considered private. Private global
* variables and functions can only be referenced within the source file in
* which they are declared. Private properties and methods should only be
* accessed by the class that defines them.
*
* @param name The name of a global variable or function, or a method or
* property.
* @return {@code true} if the name should be considered private.
*/
public boolean isPrivate(String name);
/**
* Whether this CodingConvention includes a convention for what private names should look like.
*/
public boolean hasPrivacyConvention();
/**
* Checks if the given method defines a subclass relationship,
* and if it does, returns information on that relationship. By default,
* always returns null. Meant to be overridden by subclasses.
*
* @param callNode A CALL node.
*/
public SubclassRelationship getClassesDefinedByCall(Node callNode);
/**
* Checks if the given method is a call to a class factory, such a factory returns a
* unique class.
*
* @param callNode A CALL node.
*/
public boolean isClassFactoryCall(Node callNode);
/**
* Returns true if passed a string referring to the superclass. The string
* will usually be from the string node at the right of a GETPROP, e.g.
* this.superClass_.
*/
public boolean isSuperClassReference(String propertyName);
/**
* Convenience method for determining if the node indicates the file
* is a "module" file (a file whose top level symbols are not in global
* scope).
*/
boolean extractIsModuleFile(Node node, Node parent);
/**
* Convenience method for determining provided dependencies amongst different
* JS scripts.
*/
public String extractClassNameIfProvide(Node node, Node parent);
/**
* Convenience method for determining required dependencies amongst different
* JS scripts.
*/
public String extractClassNameIfRequire(Node node, Node parent);
/**
* Function name used when exporting properties.
* Signature: fn(object, publicName, symbol).
* @return function name.
*/
public String getExportPropertyFunction();
/**
* Function name used when exporting symbols.
* Signature: fn(publicPath, object).
* @return function name.
*/
public String getExportSymbolFunction();
/**
* Checks if the given CALL node is forward-declaring any types,
* and returns the name of the types if it is.
*/
public List<String> identifyTypeDeclarationCall(Node n);
/**
* In many JS libraries, the function that produces inheritance also
* adds properties to the superclass and/or subclass.
*/
public void applySubclassRelationship(
NominalTypeBuilder parent, NominalTypeBuilder child, SubclassType type);
/**
* Function name for abstract methods. An abstract method can be assigned to
* an interface method instead of an function expression in order to avoid
* linter warnings produced by assigning a function without a return value
* where a return value is expected.
* @return function name.
*/
public String getAbstractMethodName();
/**
* Checks if the given method defines a singleton getter, and if it does,
* returns the name of the class with the singleton getter. By default, always
* returns null. Meant to be overridden by subclasses.
*
* addSingletonGetter needs a coding convention because in the general case,
* it can't be inlined. The function inliner sees that it creates an alias
* to the given class in an inner closure, and bails out.
*
* @param callNode A CALL node.
*/
public String getSingletonGetterClassName(Node callNode);
/**
* In many JS libraries, the function that adds a singleton getter to a class
* adds properties to the class.
*/
public void applySingletonGetter(
NominalTypeBuilder classType, FunctionTypeI getterType);
/**
* @return Whether the function is inlinable by convention.
*/
public boolean isInlinableFunction(Node n);
/**
* @return the delegate relationship created by the call or null.
*/
public DelegateRelationship getDelegateRelationship(Node callNode);
/**
* In many JS libraries, the function that creates a delegate relationship
* also adds properties to the delegator and delegate base.
*/
public void applyDelegateRelationship(
NominalTypeBuilder delegateSuperclass,
NominalTypeBuilder delegateBase,
NominalTypeBuilder delegator,
ObjectTypeI delegateProxy,
FunctionTypeI findDelegate);
/**
* @return the name of the delegate superclass.
*/
public String getDelegateSuperclassName();
/**
* Checks for getprops that set the calling conventions on delegate methods.
*/
public void checkForCallingConventionDefinitions(
Node getPropNode, Map<String, String> delegateCallingConventions);
/**
* Defines the delegate proxy prototype properties. Their types depend on
* properties of the delegate base methods.
*
* @param delegateProxies List of delegate proxy types.
*/
public void defineDelegateProxyPrototypeProperties(
TypeIRegistry registry,
List<NominalTypeBuilder> delegateProxies,
Map<String, String> delegateCallingConventions);
/**
* Gets the name of the global object.
*/
public String getGlobalObject();
/**
* Whether this statement is creating an alias of the global object
*/
public boolean isAliasingGlobalThis(Node n);
/**
* A Bind instance or null.
*/
public Bind describeFunctionBind(Node n);
/**
* A Bind instance or null.
*
* When seeing an expression exp1.bind(recv, arg1, ...);
* we only know that it's a function bind if exp1 has type function.
* W/out type info, exp1 has certainly a function type only if it's a
* function literal.
*
* If (the old) type checking has already happened, exp1's type is attached to
* the AST node.
* When iCheckTypes is true, describeFunctionBind looks for that type.
*
* The new type inference does not yet attach types to nodes, but we can still
* use type information in describeFunctionBind by passing true for
* callerChecksTypes.
*
* @param callerChecksTypes Trust that the caller of this method has verified
* that the bound node has a function type.
* @param iCheckTypes Check that the bound node has a function type.
*/
public Bind describeFunctionBind(
Node n, boolean callerChecksTypes, boolean iCheckTypes);
/** Bind class */
public static class Bind {
// The target of the bind action
final Node target;
// The node representing the "this" value, maybe null
final Node thisValue;
// The head of a Node list representing the parameters
final Node parameters;
public Bind(Node target, Node thisValue, Node parameters) {
this.target = target;
this.thisValue = thisValue;
this.parameters = parameters;
}
/**
* The number of parameters bound (not including the 'this' value).
*/
int getBoundParameterCount() {
if (parameters == null) {
return 0;
}
Node paramParent = parameters.getParent();
return paramParent.getChildCount() - paramParent.getIndexOfChild(parameters);
}
}
/**
* Builds a {@link Cache} instance from the given call node and returns that instance, or null
* if the {@link Node} does not resemble a cache utility call.
*
* <p>This should match calls to a cache utility method. This type of node is specially considered
* for side-effects since conventionally storing something on a cache object would be seen as a
* side-effect.
*
*/
public Cache describeCachingCall(Node node);
/** Cache class */
public static class Cache {
final Node cacheObj;
final Node key;
final Node valueFn;
final Node keyFn;
public Cache(Node cacheObj, Node key, Node valueFn, Node keyFn) {
this.cacheObj = cacheObj;
this.key = key;
this.valueFn = valueFn;
this.keyFn = keyFn;
}
}
/**
* Whether this CALL function is testing for the existence of a property.
*/
public boolean isPropertyTestFunction(Node call);
/**
* Whether this GETPROP node is an alias for an object prototype.
*/
public boolean isPrototypeAlias(Node getProp);
/**
* Whether this CALL function is returning the string name for a property, but allows renaming.
*/
public boolean isPropertyRenameFunction(String name);
/**
* Checks if the given method performs a object literal cast, and if it does,
* returns information on the cast. By default, always returns null. Meant
* to be overridden by subclasses.
*
* @param callNode A CALL node.
*/
public ObjectLiteralCast getObjectLiteralCast(Node callNode);
/**
* Gets a collection of all properties that are defined indirectly on global
* objects. (For example, Closure defines superClass_ in the goog.inherits
* call).
*/
public Collection<String> getIndirectlyDeclaredProperties();
/**
* Returns the set of AssertionFunction.
*/
public Collection<AssertionFunctionSpec> getAssertionFunctions();
/** Specify the kind of inheritance */
static enum SubclassType {
INHERITS,
MIXIN
}
/** Record subclass relations */
static class SubclassRelationship {
final SubclassType type;
final String subclassName;
final String superclassName;
public SubclassRelationship(
SubclassType type, Node subclassNode, Node superclassNode) {
Preconditions.checkArgument(
subclassNode.isQualifiedName(), "Expected qualified name, found: %s", subclassNode);
Preconditions.checkArgument(
superclassNode.isQualifiedName(), "Expected qualified name, found: %s", superclassNode);
this.type = type;
this.subclassName = subclassNode.getQualifiedName();
this.superclassName = superclassNode.getQualifiedName();
}
}
/**
* Delegates provides a mechanism and structure for identifying where classes
* can call out to optional code to augment their functionality. The optional
* code is isolated from the base code through the use of a subclass in the
* optional code derived from the delegate class in the base code.
*/
static class DelegateRelationship {
/** The subclass in the base code. */
final String delegateBase;
/** The class in the base code. */
final String delegator;
DelegateRelationship(String delegateBase, String delegator) {
this.delegateBase = delegateBase;
this.delegator = delegator;
}
}
/**
* An object literal cast provides a mechanism to cast object literals to
* other types without a warning.
*/
static class ObjectLiteralCast {
/** Type to cast to. */
final String typeName;
/** Object to cast. */
final Node objectNode;
/** Error message */
final DiagnosticType diagnosticType;
ObjectLiteralCast(String typeName, Node objectNode,
DiagnosticType diagnosticType) {
this.typeName = typeName;
this.objectNode = objectNode;
this.diagnosticType = diagnosticType;
}
}
/**
* A function that will throw an exception when either:
* -One or more of its parameters evaluate to false.
* -One or more of its parameters are not of a certain type.
*/
public class AssertionFunctionSpec {
protected final String functionName;
protected final JSTypeNative assertedType;
@Deprecated
public AssertionFunctionSpec(String functionName) {
this(functionName, null);
}
public AssertionFunctionSpec(String functionName, JSTypeNative assertedType) {
this.functionName = functionName;
this.assertedType = assertedType;
}
/** Returns the name of the function. */
public String getFunctionName() {
return functionName;
}
/**
* Returns the parameter of the assertion function that is being checked.
* @param firstParam The first parameter of the function call.
*/
public Node getAssertedParam(Node firstParam) {
return firstParam;
}
/**
* Returns the old type system type for a type assertion, or null if
* the function asserts that the node must not be null or undefined.
* @param call The asserting call
*/
public JSType getAssertedOldType(Node call, JSTypeRegistry registry) {
return assertedType != null ? registry.getNativeType(assertedType) : null;
}
}
}