mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-11-10 08:58:45 +00:00
New: The compiler will now create warnings for variables that are never read (#2871)
This new warning adds a lot of warnings in the Cappuccino frameworks. I have turned off the warning in the Jakefiles when compiling most of the Cappuccino frameworks. But it is on as default for any user projects. So there is also a new feature to turn off/on warnings as a compiler flag. These flags are (all flags are on as default): -Wunused-but-set-variable Warning when a local variable is never read. -Wshadow-ivar Warning when a local variable is shadowing an instance variable for the class. -Wcreate-global-inside-function-or-method Warning when creating a global variable inside a function or method. -Wunknown-class-or-global Warning when a class or global variable is not known. -Wunknown-ivar-type Warning when the type for an instance variable is not known. To turn off a flag add a 'no-' prefix. Example: -Wno-unused-but-set-variable For an example how to use it in a Jakefile please look at the Jakefiles in this commit.
This commit is contained in:
1 parent
b7aff28b5e
commit
1c866931f3
10 files changed
+409
-67
No files matched your search
+2
-2
@@ -34,10 +34,10 @@ appKitTask = framework ("AppKit", function(appKitTask)
|
||||
}).join(" ");
|
||||
|
||||
if ($CONFIGURATION === "Release") {
|
||||
appKitTask.setCompilerFlags("-O2 " + INCLUDES);
|
||||
appKitTask.setCompilerFlags("-O2 -Wno-unused-but-set-variable " + INCLUDES);
|
||||
}
|
||||
else
|
||||
appKitTask.setCompilerFlags("-DDEBUG -g -S --inline-msg-send " + INCLUDES);
|
||||
appKitTask.setCompilerFlags("-DDEBUG -g -S --inline-msg-send -Wno-unused-but-set-variable " + INCLUDES);
|
||||
});
|
||||
|
||||
$BUILD_CJS_CAPPUCCINO_APPKIT = FILE.join($BUILD_CJS_CAPPUCCINO_FRAMEWORKS, "AppKit");
|
||||
|
||||
@@ -20,9 +20,9 @@ blendKitTask = framework ("BlendKit", function(blendKitTask)
|
||||
blendKitTask.setFlattensSources(true); // FIXME: how do we non flatten?
|
||||
|
||||
if ($CONFIGURATION === "Release")
|
||||
blendKitTask.setCompilerFlags("-O2");
|
||||
blendKitTask.setCompilerFlags("-O2 -Wno-unused-but-set-variable");
|
||||
else
|
||||
blendKitTask.setCompilerFlags("-DDEBUG -g");
|
||||
blendKitTask.setCompilerFlags("-DDEBUG -g -Wno-unused-but-set-variable");
|
||||
});
|
||||
|
||||
$BUILD_CJS_PRODUCT_BLENDKIT = FILE.join($BUILD_CJS_CAPPUCCINO_FRAMEWORKS, "BlendKit");
|
||||
|
||||
+2
-2
@@ -51,9 +51,9 @@ foundationTask = framework ("Foundation", function(foundationTask)
|
||||
INCLUDES = "--include \"../AppKit/Platform/Platform.h\" " + INCLUDES;
|
||||
|
||||
if ($CONFIGURATION === "Release")
|
||||
foundationTask.setCompilerFlags("-O2 " + INCLUDES);
|
||||
foundationTask.setCompilerFlags("-O2 -Wno-unused-but-set-variable " + INCLUDES);
|
||||
else
|
||||
foundationTask.setCompilerFlags("-DDEBUG -g -S --inline-msg-send " + INCLUDES);
|
||||
foundationTask.setCompilerFlags("-DDEBUG -g -S --inline-msg-send -Wno-unused-but-set-variable " + INCLUDES);
|
||||
});
|
||||
|
||||
$BUILD_CJS_FOUNDATION = FILE.join($BUILD_CJS_CAPPUCCINO_FRAMEWORKS, "Foundation");
|
||||
|
||||
@@ -256,14 +256,20 @@ exports.main = function(args)
|
||||
if (argv[0] === "--help" || argv[0].substr(0, 1) == '-')
|
||||
{
|
||||
print("Usage (objjc 2.0): " + args[0] + " [options] [--] file...");
|
||||
print(" -p, --print print the output directly to stdout");
|
||||
print(" --unmarked don't tag the output with @STATIC header");
|
||||
print(" -p, --print print the output directly to stdout");
|
||||
print(" --unmarked don't tag the output with @STATIC header");
|
||||
print("");
|
||||
print(" -T, --dont-include-type-signatures include type signatures in the compiled output");
|
||||
print(" -g, --include-debug-symbols include debug symbols in the compiled output");
|
||||
print(" -T, --include-type-signatures include type signatures in the compiled output");
|
||||
print(" -O, --compress compress the compiled output");
|
||||
print(" -O2, --inline-msg-send inline objj_msgSend function in the compiled output");
|
||||
print(" -T, --dont-include-type-signatures include type signatures in the compiled output");
|
||||
print(" -g, --include-debug-symbols include debug symbols in the compiled output");
|
||||
print(" -T, --include-type-signatures include type signatures in the compiled output");
|
||||
print(" -O, --compress compress the compiled output");
|
||||
print(" -O2, --inline-msg-send inline objj_msgSend function in the compiled output");
|
||||
print(" -Wno-unused-but-set-variable turn off warning when a local variable is never read");
|
||||
print(" -Wno-shadow-ivar turn off warning when a local variable is shadowing an instance variable for the class");
|
||||
print(" -Wno-create-global-inside-function-or-method turn off warning when creating a global variable inside a function or method");
|
||||
print(" -Wno-unknown-class-or-global. turn off warning when a class or global variable is not known");
|
||||
print(" -Wno-unknown-ivar-type turn off warning when the type for an instance variable is not known");
|
||||
print(" To turn on a warning flag remove the 'no-' prefix. Example: -Wunused-but-set-variable");
|
||||
print("");
|
||||
print(" --help print this help");
|
||||
return;
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
|
||||
require("../common.jake");
|
||||
|
||||
// Make sure we can use new functions in an in old javascript engines like Rhino
|
||||
// This is only needed if new things are introduced in OldBrowserCompatibility.js
|
||||
// as we are running in an already built Objective-J environment
|
||||
require("./OldBrowserCompatibility");
|
||||
|
||||
var FILE = require("file"),
|
||||
OS = require("os"),
|
||||
stream = require("narwhal/term").stream;
|
||||
@@ -49,7 +54,7 @@ filedir($BUILD_BROWSER_FILE, $BROWSER_FILES, function(aTask)
|
||||
{
|
||||
gcc($BROWSER_FILE,
|
||||
$BUILD_BROWSER_FILE,
|
||||
environmentFlags("Browser", "ObjJ").concat($INCLUDE_FLAGS, $DEBUG_FLAGS), $CONFIGURATION !== "Debug");
|
||||
environmentFlags("Browser", "ObjJ").concat($INCLUDE_FLAGS, $DEBUG_FLAGS, ["-Wno-unused-but-set-variable"]), $CONFIGURATION !== "Debug");
|
||||
});
|
||||
|
||||
$LICENSE = FILE.join("CommonJS", "lib", "objective-j", "jake", "LICENSES", "LGPL-v2.1");
|
||||
@@ -78,7 +83,7 @@ new FileList("CommonJS/**/*").forEach(function(aFilename)
|
||||
else
|
||||
gcc(aFilename,
|
||||
buildFilename,
|
||||
environmentFlags("CommonJS", "ObjJ").concat($INCLUDE_FLAGS, $DEBUG_FLAGS), false);
|
||||
environmentFlags("CommonJS", "ObjJ").concat($INCLUDE_FLAGS, $DEBUG_FLAGS, ["-Wno-unused-but-set-variable"]), false);
|
||||
});
|
||||
|
||||
// HACK: narwhal should copy permissions
|
||||
|
||||
@@ -93,6 +93,24 @@ Scope.prototype.getIvarForCurrentClass = function(/* String */ ivarName)
|
||||
return null;
|
||||
}
|
||||
|
||||
Scope.prototype.getLvarScope = function(/* String */ lvarName, /* BOOL */ stopAtMethod)
|
||||
{
|
||||
if (this.vars)
|
||||
{
|
||||
var lvar = this.vars[lvarName];
|
||||
if (lvar)
|
||||
return this;
|
||||
}
|
||||
|
||||
var prev = this.prev;
|
||||
|
||||
// Stop at the method declaration
|
||||
if (prev && (!stopAtMethod || !this.methodType))
|
||||
return prev.getLvarScope(lvarName, stopAtMethod);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Scope.prototype.getLvar = function(/* String */ lvarName, /* BOOL */ stopAtMethod)
|
||||
{
|
||||
if (this.vars)
|
||||
@@ -111,6 +129,13 @@ Scope.prototype.getLvar = function(/* String */ lvarName, /* BOOL */ stopAtMetho
|
||||
return null;
|
||||
}
|
||||
|
||||
Scope.prototype.getVarScope = function()
|
||||
{
|
||||
var prev = this.prev;
|
||||
|
||||
return prev ? prev.getVarScope() : this;
|
||||
}
|
||||
|
||||
Scope.prototype.currentMethodType = function()
|
||||
{
|
||||
return this.methodType ? this.methodType : this.prev ? this.prev.currentMethodType() : null;
|
||||
@@ -145,6 +170,23 @@ Scope.prototype.addMaybeWarning = function(warning)
|
||||
}
|
||||
}
|
||||
|
||||
Scope.prototype.variablesNotReadWarnings = function()
|
||||
{
|
||||
var compiler = this.compiler;
|
||||
|
||||
// The warning option must be turned on. We can't be top scope. The scope must have some variables
|
||||
if (compiler.options.warnings.includes(warningUnusedButSetVariable) && this.prev && this.vars) for (var key in this.vars)
|
||||
{
|
||||
var lvar = this.vars[key];
|
||||
|
||||
if (!lvar.isRead && lvar.type === "var")
|
||||
{
|
||||
//print("Variable '" + key + "' is never read: " + lvar.type + ", line: " + lvar.node.start);
|
||||
compiler.addWarning(createMessage("Variable '" + key + "' is never read", lvar.node, compiler.source));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Scope.prototype.maybeWarnings = function()
|
||||
{
|
||||
return this.rootScope()._maybeWarnings;
|
||||
@@ -257,6 +299,51 @@ Scope.prototype.formatDescription = function(index, formatDescription, useOverri
|
||||
}
|
||||
}
|
||||
|
||||
var FunctionScope = function(prev, base)
|
||||
{
|
||||
Scope.call(this, prev, base);
|
||||
}
|
||||
|
||||
FunctionScope.prototype = Object.create(Scope.prototype);
|
||||
|
||||
FunctionScope.prototype.constructor = FunctionScope;
|
||||
|
||||
FunctionScope.prototype.getVarScope = function()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
FunctionScope.prototype.variablesNotReadWarnings = function()
|
||||
{
|
||||
Scope.prototype.variablesNotReadWarnings.call(this);
|
||||
|
||||
var prev = this.prev;
|
||||
|
||||
// Any possible hoisted variable in this scope has to be moved to the previous scope if it is not declared in the previsous scope
|
||||
// We can't be top scope. The scope must have some possible hoisted variables
|
||||
if (prev && this.possibleHoistedVariables) for (var key in this.possibleHoistedVariables)
|
||||
{
|
||||
var possibleHoistedVariable = this.possibleHoistedVariables[key];
|
||||
|
||||
if (possibleHoistedVariable)
|
||||
{
|
||||
var varInPrevScope = prev.vars && prev.vars[key];
|
||||
|
||||
if (varInPrevScope != null)
|
||||
{
|
||||
var prevPossibleHoistedVariable = (prev.possibleHoistedVariables || (prev.possibleHoistedVariables = Object.create(null)))[key];
|
||||
|
||||
if (prevPossibleHoistedVariable == null) {
|
||||
prev.possibleHoistedVariables[key] = possibleHoistedVariable;
|
||||
} else {
|
||||
throw new Error("Internal inconsistency, previous scope should not have this possible hoisted variable '" + key + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var GlobalVariableMaybeWarning = function(/* String */ aMessage, /* SpiderMonkey AST node */ node, /* String */ code)
|
||||
{
|
||||
this.message = createMessage(aMessage, node, code);
|
||||
@@ -623,6 +710,20 @@ var wordPrefixOperators = acorn.makePredicate("delete in instanceof new typeof v
|
||||
var isLogicalBinary = acorn.makePredicate("LogicalExpression BinaryExpression");
|
||||
var isInInstanceof = acorn.makePredicate("in instanceof");
|
||||
|
||||
var warningUnusedButSetVariable = {name: "unused-but-set-variable"};
|
||||
var warningShadowIvar = {name: "shadow-ivar"};
|
||||
var warningCreateGlobalInsideFunctionOrMethod = {name: "create-global-inside-function-or-method"};
|
||||
var warningUnknownClassOrGlobal = {name: "unknown-class-or-global"};
|
||||
var warningUnknownIvarType = {name: "unknown-ivar-type"};
|
||||
|
||||
var AllWarnings = [warningUnusedButSetVariable, warningShadowIvar, warningCreateGlobalInsideFunctionOrMethod, warningUnknownClassOrGlobal, warningUnknownIvarType];
|
||||
|
||||
exports.warningUnusedButSetVariable = warningUnusedButSetVariable;
|
||||
exports.warningShadowIvar = warningShadowIvar;
|
||||
exports.warningCreateGlobalInsideFunctionOrMethod = warningCreateGlobalInsideFunctionOrMethod;
|
||||
exports.warningUnknownClassOrGlobal = warningUnknownClassOrGlobal;
|
||||
exports.warningUnknownIvarType = warningUnknownIvarType;
|
||||
|
||||
// A optional argument can be given to further configure
|
||||
// the compiler. These options are recognized:
|
||||
|
||||
@@ -693,6 +794,9 @@ var isInInstanceof = acorn.makePredicate("in instanceof");
|
||||
// Turn off `inlineMsgSendFunctions` to use message send functions. Needed to use message send decorators.
|
||||
inlineMsgSendFunctions: true,
|
||||
|
||||
// `warning` includes the warnings that are turned on. It is just used for some warnings.
|
||||
warnings: [warningUnusedButSetVariable, warningShadowIvar, warningCreateGlobalInsideFunctionOrMethod, warningUnknownClassOrGlobal, warningUnknownIvarType],
|
||||
|
||||
// An array of macro objects and/or text definitions may be passed in.
|
||||
// Definitions may be in one of two forms:
|
||||
// macro
|
||||
@@ -1081,6 +1185,25 @@ exports.parseGccCompilerFlags = function(/* String */ compilerFlags)
|
||||
|
||||
(objjcFlags.macros || (objjcFlags.macros = [])).push(macroDefinition);
|
||||
}
|
||||
else if (argument.indexOf("-W") === 0) {
|
||||
// TODO: Check if the warning name is a valid one. Now we just grab what is written and set/remove it.
|
||||
var isNo = argument.indexOf("no-", 2) === 2
|
||||
var warningName = argument.substring(isNo ? 5 : 2);
|
||||
var indexOfWarning = (objjcFlags.warnings || (objjcFlags.warnings = defaultOptions.warnings.slice())).findIndex(function (element) { return element.name === warningName });
|
||||
|
||||
if (isNo) {
|
||||
if (indexOfWarning !== -1) {
|
||||
// remove if it exists
|
||||
objjcFlags.warnings.splice(indexOfWarning, 1);
|
||||
}
|
||||
} else {
|
||||
if (indexOfWarning === -1) {
|
||||
// Add if it does not exists
|
||||
var theWarning = AllWarnings.find(function (element) { return element.name === warningName });
|
||||
if (theWarning) objjcFlags.warnings.push(theWarning);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return objjcFlags;
|
||||
@@ -1137,7 +1260,7 @@ ObjJAcornCompiler.prototype.prettifyMessage = function(/* Message */ aMessage)
|
||||
|
||||
message += (new Array((aMessage.messageOnColumn || 0) + 1)).join(" ");
|
||||
if (line) message += (new Array(Math.min(1, line.length || 1) + 1)).join("^") + "\n";
|
||||
message += aMessage.messageType + " line " + aMessage.messageOnLine + " in " + this.URL + ": " + aMessage.message;
|
||||
message += aMessage.messageType + " line " + aMessage.messageOnLine + " in " + this.URL + ":" + aMessage.messageOnLine + ": " + aMessage.message;
|
||||
|
||||
return message;
|
||||
}
|
||||
@@ -1735,6 +1858,7 @@ TryStatement: function(node, st, c, format) {
|
||||
inner.skipIndentation = true;
|
||||
inner.endOfScopeBody = true;
|
||||
c(handler.body, inner, "ScopeBody");
|
||||
inner.variablesNotReadWarnings();
|
||||
indentation = indentation.substring(indentationSize);
|
||||
inner.copyAddedSelfToIvarsToParent();
|
||||
}
|
||||
@@ -1914,7 +2038,7 @@ Function: function(node, st, c, format) {
|
||||
var compiler = st.compiler,
|
||||
generate = compiler.generate,
|
||||
buffer = compiler.jsBuffer,
|
||||
inner = new Scope(st),
|
||||
inner = new FunctionScope(st),
|
||||
decl = node.type == "FunctionDeclaration",
|
||||
id = node.id;
|
||||
|
||||
@@ -1962,12 +2086,14 @@ Function: function(node, st, c, format) {
|
||||
indentation += indentStep;
|
||||
inner.endOfScopeBody = true;
|
||||
c(node.body, inner, "ScopeBody");
|
||||
inner.variablesNotReadWarnings();
|
||||
indentation = indentation.substring(indentationSize);
|
||||
inner.copyAddedSelfToIvarsToParent();
|
||||
},
|
||||
VariableDeclaration: function(node, st, c, format) {
|
||||
var compiler = st.compiler,
|
||||
generate = compiler.generate,
|
||||
varScope = st.getVarScope(),
|
||||
buffer;
|
||||
if (generate) {
|
||||
buffer = compiler.jsBuffer;
|
||||
@@ -1976,7 +2102,24 @@ VariableDeclaration: function(node, st, c, format) {
|
||||
}
|
||||
for (var i = 0; i < node.declarations.length; ++i) {
|
||||
var decl = node.declarations[i],
|
||||
identifier = decl.id.name;
|
||||
identifier = decl.id.name,
|
||||
possibleHoistedVariable = varScope.possibleHoistedVariables && varScope.possibleHoistedVariables[identifier],
|
||||
variableDeclaration = {type: "var", node: decl.id, isRead: (possibleHoistedVariable ? possibleHoistedVariable.isRead : 0)};
|
||||
|
||||
// Make sure we count the access for this varaible if it is hoisted.
|
||||
// Check if this variable has already been accessed above this declaration
|
||||
if (possibleHoistedVariable) {
|
||||
// 'variableDeclaration' is already marked as read. This was done by adding the already read amount above.
|
||||
|
||||
// Substract the same amount from possible local variable higher up in the hierarchy that is shadowed by this declaration
|
||||
if (possibleHoistedVariable.variable) {
|
||||
possibleHoistedVariable.variable.isRead -= possibleHoistedVariable.isRead;
|
||||
}
|
||||
// Remove it as we don't need to care about this variable anymore.
|
||||
varScope.possibleHoistedVariables[identifier] = null;
|
||||
}
|
||||
varScope.vars[identifier] = variableDeclaration;
|
||||
|
||||
if (i)
|
||||
if (generate) {
|
||||
if (format) {
|
||||
@@ -1991,7 +2134,7 @@ VariableDeclaration: function(node, st, c, format) {
|
||||
}
|
||||
}
|
||||
}
|
||||
st.vars[identifier] = {type: "var", node: decl.id};
|
||||
|
||||
c(decl.id, st, "IdentifierName");
|
||||
if (decl.init) {
|
||||
if (generate) {
|
||||
@@ -2015,8 +2158,11 @@ VariableDeclaration: function(node, st, c, format) {
|
||||
for (var i = 0, size = addedSelfToIvar.length; i < size; i++) {
|
||||
var dict = addedSelfToIvar[i];
|
||||
atoms[dict.index] = "";
|
||||
compiler.addWarning(createMessage("Local declaration of '" + identifier + "' hides instance variable", dict.node, compiler.source));
|
||||
if (compiler.options.warnings.includes(warningShadowIvar)) compiler.addWarning(createMessage("Local declaration of '" + identifier + "' hides instance variable", dict.node, compiler.source));
|
||||
}
|
||||
// Add a read mark to the local variable for each time it is used.
|
||||
variableDeclaration.isRead += size;
|
||||
// Remove the variable from list of instance variable uses.
|
||||
st.addedSelfToIvars[identifier] = [];
|
||||
}
|
||||
}
|
||||
@@ -2239,9 +2385,9 @@ AssignmentExpression: function(node, st, c, format) {
|
||||
if (nodeLeft.type === "Identifier" && nodeLeft.name === "self") {
|
||||
var lVar = st.getLvar("self", true);
|
||||
if (lVar) {
|
||||
var lVarScope = lVar.scope;
|
||||
if (lVarScope)
|
||||
lVarScope.assignmentToSelf = true;
|
||||
var lvarScope = lVar.scope;
|
||||
if (lvarScope)
|
||||
lvarScope.assignmentToSelf = true;
|
||||
}
|
||||
}
|
||||
(generate && nodePrecedence(node, nodeLeft) ? surroundExpression(c) : c)(nodeLeft, st, "Expression");
|
||||
@@ -2352,48 +2498,88 @@ Identifier: function(node, st, c) {
|
||||
var compiler = st.compiler,
|
||||
generate = compiler.generate,
|
||||
identifier = node.name;
|
||||
if (st.currentMethodType() === "-" && !st.secondMemberExpression && !st.isPropertyKey)
|
||||
{
|
||||
var lvar = st.getLvar(identifier, true), // Only look inside method
|
||||
ivar = compiler.getIvarForClass(identifier, st);
|
||||
|
||||
if (ivar)
|
||||
if (!st.isPropertyKey) {
|
||||
var lvarScope = st.getLvarScope(identifier, true); // Only look inside method/function scope
|
||||
var lvar = lvarScope.vars && lvarScope.vars[identifier];
|
||||
if (!st.secondMemberExpression && st.currentMethodType() === "-")
|
||||
{
|
||||
if (lvar)
|
||||
compiler.addWarning(createMessage("Local declaration of '" + identifier + "' hides instance variable", node, compiler.source));
|
||||
else
|
||||
{
|
||||
var nodeStart = node.start;
|
||||
var ivar = compiler.getIvarForClass(identifier, st);
|
||||
|
||||
if (!generate) do { // The Spider Monkey AST tree includes any parentheses in start and end properties so we have to make sure we skip those
|
||||
compiler.jsBuffer.concat(compiler.source.substring(compiler.lastPos, nodeStart));
|
||||
compiler.lastPos = nodeStart;
|
||||
} while (compiler.source.substr(nodeStart++, 1) === "(")
|
||||
// Save the index in where the "self." string is stored and the node.
|
||||
// These will be used if we find a variable declaration that is hoisting this identifier.
|
||||
((st.addedSelfToIvars || (st.addedSelfToIvars = Object.create(null)))[identifier] || (st.addedSelfToIvars[identifier] = [])).push({node: node, index: compiler.jsBuffer.length()});
|
||||
compiler.jsBuffer.concat("self.", node);
|
||||
}
|
||||
} else if (!reservedIdentifiers(identifier)) { // Don't check for warnings if it is a reserved word like self, localStorage, _cmd, etc...
|
||||
var message,
|
||||
classOrGlobal = typeof global[identifier] !== "undefined" || (typeof window !== 'undefined' && typeof window[identifier] !== "undefined") || compiler.getClassDef(identifier),
|
||||
globalVar = st.getLvar(identifier);
|
||||
if (classOrGlobal && (!globalVar || globalVar.type !== "class")) { // It can't be declared with a @class statement.
|
||||
/* Turned off this warning as there are many many warnings when compiling the Cappuccino frameworks - Martin
|
||||
if (ivar)
|
||||
{
|
||||
if (lvar) {
|
||||
message = compiler.addWarning(createMessage("Local declaration of '" + identifier + "' hides global variable", node, compiler.source));
|
||||
}*/
|
||||
} else if (!globalVar) {
|
||||
if (st.assignment) {
|
||||
message = new GlobalVariableMaybeWarning("Creating global variable inside function or method '" + identifier + "'", node, compiler.source);
|
||||
// Turn off these warnings for this identifier, we only want one.
|
||||
st.vars[identifier] = {type: "remove global warning", node: node};
|
||||
if (compiler.options.warnings.includes(warningShadowIvar)) compiler.addWarning(createMessage("Local declaration of '" + identifier + "' hides instance variable", node, compiler.source));
|
||||
}
|
||||
else
|
||||
{
|
||||
var nodeStart = node.start;
|
||||
|
||||
if (!generate) do { // The Spider Monkey AST tree includes any parentheses in start and end properties so we have to make sure we skip those
|
||||
compiler.jsBuffer.concat(compiler.source.substring(compiler.lastPos, nodeStart));
|
||||
compiler.lastPos = nodeStart;
|
||||
} while (compiler.source.substr(nodeStart++, 1) === "(")
|
||||
// Save the index in where the "self." string is stored and the node.
|
||||
// These will be used if we find a variable declaration that is hoisting this identifier.
|
||||
((st.addedSelfToIvars || (st.addedSelfToIvars = Object.create(null)))[identifier] || (st.addedSelfToIvars[identifier] = [])).push({node: node, index: compiler.jsBuffer.length()});
|
||||
compiler.jsBuffer.concat("self.", node);
|
||||
}
|
||||
} else if (!reservedIdentifiers(identifier)) { // Don't check for warnings if it is a reserved word like self, localStorage, _cmd, etc...
|
||||
var message,
|
||||
classOrGlobal = typeof global[identifier] !== "undefined" || (typeof window !== 'undefined' && typeof window[identifier] !== "undefined") || compiler.getClassDef(identifier),
|
||||
globalVar = st.getLvar(identifier);
|
||||
if (classOrGlobal && (!globalVar || globalVar.type !== "class")) { // It can't be declared with a @class statement.
|
||||
/* Turned off this warning as there are many many warnings when compiling the Cappuccino frameworks - Martin
|
||||
if (lvar) {
|
||||
message = compiler.addWarning(createMessage("Local declaration of '" + identifier + "' hides global variable", node, compiler.source));
|
||||
}*/
|
||||
} else if (!globalVar) {
|
||||
if (st.assignment && compiler.options.warnings.includes(warningCreateGlobalInsideFunctionOrMethod)) {
|
||||
message = new GlobalVariableMaybeWarning("Creating global variable inside function or method '" + identifier + "'", node, compiler.source);
|
||||
// Turn off these warnings for this identifier, we only want one.
|
||||
st.vars[identifier] = {type: "remove global warning", node: node};
|
||||
} else if (compiler.options.warnings.includes(warningUnknownClassOrGlobal)){
|
||||
message = new GlobalVariableMaybeWarning("Using unknown class or uninitialized global variable '" + identifier + "'", node, compiler.source);
|
||||
}
|
||||
}
|
||||
if (message)
|
||||
st.addMaybeWarning(message);
|
||||
}
|
||||
}
|
||||
if (!st.assignment || !st.secondMemberExpression) {
|
||||
if (lvar) {
|
||||
lvar.isRead++;
|
||||
} else {
|
||||
// If the var is not declared in current var scope (function scope) we need to save which var it is as it can be hoisted.
|
||||
// First check if the variable is declared higher up in the scope hierarchy
|
||||
lvarScope = lvarScope.getLvarScope(identifier);
|
||||
lvar = lvarScope.vars && lvarScope.vars[identifier];
|
||||
// We will mark it as read.
|
||||
if (lvar) {
|
||||
lvar.isRead++;
|
||||
}
|
||||
|
||||
// The variable can be declared later on in this function / method scope.
|
||||
// It can also be declared later on in a higher scope.
|
||||
// We create a list of possible variables that will be used if it is declared.
|
||||
// We collect how many times the variable is read and a reference to a possible variable in a
|
||||
var possibleHoistedVariable = (lvarScope.possibleHoistedVariables || (lvarScope.possibleHoistedVariables = Object.create(null)))[identifier];
|
||||
|
||||
if (possibleHoistedVariable == null) {
|
||||
var possibleHoistedVariable = {isRead: 1};
|
||||
lvarScope.possibleHoistedVariables[identifier] = possibleHoistedVariable;
|
||||
} else {
|
||||
message = new GlobalVariableMaybeWarning("Using unknown class or uninitialized global variable '" + identifier + "'", node, compiler.source);
|
||||
possibleHoistedVariable.isRead++;
|
||||
}
|
||||
|
||||
if (lvar) {
|
||||
// If the var and scope are already set it should not be different from what we found now.
|
||||
if ((possibleHoistedVariable.variable && possibleHoistedVariable.variable !== lvar) || (possibleHoistedVariable.varScope && possibleHoistedVariable.varScope !== lvarScope)) {
|
||||
throw new Error("Internal inconsistency, var or scope is not the same");
|
||||
}
|
||||
possibleHoistedVariable.variable = lvar;
|
||||
possibleHoistedVariable.varScope = lvarScope;
|
||||
}
|
||||
}
|
||||
if (message)
|
||||
st.addMaybeWarning(message);
|
||||
}
|
||||
}
|
||||
if (generate) compiler.jsBuffer.concat(identifier, node, identifier === "self" ? "self" : null);
|
||||
@@ -2790,7 +2976,7 @@ ClassDeclarationStatement: function(node, st, c, format) {
|
||||
var isTypeDefined = !ivarTypeIsClass || typeof global[ivarType] !== "undefined" || typeof window[ivarType] !== "undefined"
|
||||
|| compiler.getClassDef(ivarType) || compiler.getTypeDef(ivarType) || ivarType == classDef.name;
|
||||
|
||||
if (!isTypeDefined)
|
||||
if (!isTypeDefined && compiler.options.warnings.includes(warningUnknownIvarType))
|
||||
compiler.addWarning(createMessage("Unknown type '" + ivarType + "' for ivar '" + ivarName + "'", ivarDecl.ivartype, compiler.source));
|
||||
|
||||
if (generateObjJ) {
|
||||
@@ -3133,7 +3319,7 @@ MethodDeclarationStatement: function(node, st, c) {
|
||||
var compiler = st.compiler,
|
||||
generate = compiler.generate,
|
||||
saveJSBuffer = compiler.jsBuffer,
|
||||
methodScope = new Scope(st),
|
||||
methodScope = new FunctionScope(st),
|
||||
isInstanceMethodType = node.methodtype === '-',
|
||||
selectors = node.selectors,
|
||||
nodeArguments = node.arguments,
|
||||
@@ -3265,6 +3451,7 @@ MethodDeclarationStatement: function(node, st, c) {
|
||||
indentation += indentStep;
|
||||
methodScope.endOfScopeBody = true;
|
||||
c(node.body, methodScope, "Statement");
|
||||
methodScope.variablesNotReadWarnings();
|
||||
indentation = indentation.substring(indentationSize);
|
||||
if (!generate) compiler.jsBuffer.concat(compiler.source.substring(compiler.lastPos, node.body.end));
|
||||
|
||||
|
||||
@@ -116,6 +116,53 @@ if (!Array.prototype.indexOf)
|
||||
};
|
||||
}
|
||||
|
||||
// https://tc39.github.io/ecma262/#sec-array.prototype.findindex
|
||||
if (!Array.prototype.findIndex) {
|
||||
Object.defineProperty(Array.prototype, 'findIndex', {
|
||||
value: function(predicate) {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
if (this == null) {
|
||||
throw new TypeError('"this" is null or not defined');
|
||||
}
|
||||
|
||||
var o = Object(this);
|
||||
|
||||
// 2. Let len be ? ToLength(? Get(O, "length")).
|
||||
var len = o.length >>> 0;
|
||||
|
||||
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
||||
if (typeof predicate !== 'function') {
|
||||
throw new TypeError('predicate must be a function');
|
||||
}
|
||||
|
||||
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
var thisArg = arguments[1];
|
||||
|
||||
// 5. Let k be 0.
|
||||
var k = 0;
|
||||
|
||||
// 6. Repeat, while k < len
|
||||
while (k < len) {
|
||||
// a. Let Pk be ! ToString(k).
|
||||
// b. Let kValue be ? Get(O, Pk).
|
||||
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
|
||||
// d. If testResult is true, return k.
|
||||
var kValue = o[k];
|
||||
if (predicate.call(thisArg, kValue, k, o)) {
|
||||
return k;
|
||||
}
|
||||
// e. Increase k by 1.
|
||||
k++;
|
||||
}
|
||||
|
||||
// 7. Return -1.
|
||||
return -1;
|
||||
},
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
}
|
||||
|
||||
// ECMAScript 6 has added this. It is copied from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String
|
||||
if (!String.prototype.startsWith) {
|
||||
String.prototype.startsWith = function(searchString, position){
|
||||
@@ -135,4 +182,101 @@ if (!String.prototype.endsWith) {
|
||||
var lastIndex = subjectString.indexOf(searchString, position);
|
||||
return lastIndex !== -1 && lastIndex === position;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// ECMAScript 6 has added this. It is copied from https://developer.mozilla.org/nl/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
|
||||
// https://tc39.github.io/ecma262/#sec-array.prototype.includes
|
||||
if (!Array.prototype.includes) {
|
||||
Object.defineProperty(Array.prototype, 'includes', {
|
||||
value: function(searchElement, fromIndex) {
|
||||
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
if (this == null) {
|
||||
throw new TypeError('"this" is null or not defined');
|
||||
}
|
||||
|
||||
var o = Object(this);
|
||||
|
||||
// 2. Let len be ? ToLength(? Get(O, "length")).
|
||||
var len = o.length >>> 0;
|
||||
|
||||
// 3. If len is 0, return false.
|
||||
if (len === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. Let n be ? ToInteger(fromIndex).
|
||||
// (If fromIndex is undefined, this step produces the value 0.)
|
||||
var n = fromIndex | 0;
|
||||
|
||||
// 5. If n ≥ 0, then
|
||||
// a. Let k be n.
|
||||
// 6. Else n < 0,
|
||||
// a. Let k be len + n.
|
||||
// b. If k < 0, let k be 0.
|
||||
var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
|
||||
|
||||
// 7. Repeat, while k < len
|
||||
while (k < len) {
|
||||
// a. Let elementK be the result of ? Get(O, ! ToString(k)).
|
||||
// b. If SameValueZero(searchElement, elementK) is true, return true.
|
||||
// c. Increase k by 1.
|
||||
// NOTE: === provides the correct "SameValueZero" comparison needed here.
|
||||
if (o[k] === searchElement) {
|
||||
return true;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
// 8. Return false
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// https://tc39.github.io/ecma262/#sec-array.prototype.find
|
||||
if (!Array.prototype.find) {
|
||||
Object.defineProperty(Array.prototype, 'find', {
|
||||
value: function(predicate) {
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
if (this == null) {
|
||||
throw TypeError('"this" is null or not defined');
|
||||
}
|
||||
|
||||
var o = Object(this);
|
||||
|
||||
// 2. Let len be ? ToLength(? Get(O, "length")).
|
||||
var len = o.length >>> 0;
|
||||
|
||||
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
||||
if (typeof predicate !== 'function') {
|
||||
throw TypeError('predicate must be a function');
|
||||
}
|
||||
|
||||
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||||
var thisArg = arguments[1];
|
||||
|
||||
// 5. Let k be 0.
|
||||
var k = 0;
|
||||
|
||||
// 6. Repeat, while k < len
|
||||
while (k < len) {
|
||||
// a. Let Pk be ! ToString(k).
|
||||
// b. Let kValue be ? Get(O, Pk).
|
||||
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
|
||||
// d. If testResult is true, return kValue.
|
||||
var kValue = o[k];
|
||||
if (predicate.call(thisArg, kValue, k, o)) {
|
||||
return kValue;
|
||||
}
|
||||
// e. Increase k by 1.
|
||||
k++;
|
||||
}
|
||||
|
||||
// 7. Return undefined.
|
||||
return undefined;
|
||||
},
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
@implementation IvarTestClass : CPObject
|
||||
{
|
||||
id ivar1 @accessors;
|
||||
var ivar2 @accessors(readonly);
|
||||
id ivar2 @accessors(readonly);
|
||||
CPNumber ivar3;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,14 +55,14 @@ function cleanup() {
|
||||
[self assert:"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"><plist version = \"1.0\"><array><dict><key>line</key><integer>1</integer><key>sourcePath</key><string>" + rootDirectory + "/objjErrorTestFile.j</string><key>message</key><string>\
|
||||
\n@implementation AppController : CPObject{}@end\
|
||||
\n ^\
|
||||
\nERROR line 1 in file:" + rootDirectory + "/objjErrorTestFile.j: Can't find superclass CPObject</string></dict></array></plist>\n" equals:p.stdout.read() message:"objj failed"];
|
||||
\nERROR line 1 in file:" + rootDirectory + "/objjErrorTestFile.j:1: Can't find superclass CPObject</string></dict></array></plist>\n" equals:p.stdout.read() message:"objj failed"];
|
||||
|
||||
var p = OS.popen(["objj", "-x", "objjWarningTestFile.j"]);
|
||||
var pp = p.stdout.read();
|
||||
[self assert:0 equals:p.wait() message:"objj failed"];
|
||||
[self assert:"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"><plist version = \"1.0\"><array><dict><key>line</key><integer>1</integer><key>sourcePath</key><string>" + rootDirectory + "/objjWarningTestFile.j</string><key>message</key><string>\n@import <Foundation/Foundation.j>@implementation AppController : CPObject{CPWindow theWindow;}@end\
|
||||
\n ^\
|
||||
\nWARNING line 1 in file:" + rootDirectory + "/objjWarningTestFile.j: Unknown type 'CPWindow' for ivar 'theWindow'</string></dict></array></plist>\n" equals:pp message:"objj failed"];
|
||||
\nWARNING line 1 in file:" + rootDirectory + "/objjWarningTestFile.j:1: Unknown type 'CPWindow' for ivar 'theWindow'</string></dict></array></plist>\n" equals:pp message:"objj failed"];
|
||||
|
||||
status = OS.system(["objj", "-m", "ToolsTestApp/AppController.j", "ToolsTestApp/AppController.j"]);
|
||||
[self assert:0 equals:status message:"objj failed with several files"];
|
||||
|
||||
@@ -23,9 +23,9 @@ app ("nib2cib", function(nib2cibTask)
|
||||
nib2cibTask.setFlattensSources(true);
|
||||
|
||||
if ($CONFIGURATION === "Release")
|
||||
nib2cibTask.setCompilerFlags("-O");
|
||||
nib2cibTask.setCompilerFlags("-O2 -Wno-unused-but-set-variable ");
|
||||
else
|
||||
nib2cibTask.setCompilerFlags("-DDEBUG -g");
|
||||
nib2cibTask.setCompilerFlags("-DDEBUG -g -Wno-unused-but-set-variable ");
|
||||
});
|
||||
|
||||
$BUILD_CJS_NIB2CIB = FILE.join($BUILD_CJS_CAPPUCCINO_BIN, 'nib2cib');
|
||||
|
||||
Reference in new issue
Block a user