Import of the watch repository from Pebble

This commit is contained in:
Matthieu Jeanson 2024-12-12 16:43:03 -08:00 committed by Katharine Berry
commit 3b92768480
10334 changed files with 2564465 additions and 0 deletions

View file

@ -0,0 +1,17 @@
<?php
// Copyright 2024 Google LLC
//
// 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.
phutil_register_library('linters', __FILE__);

View file

@ -0,0 +1,38 @@
<?php
// Copyright 2024 Google LLC
//
// 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.
/**
* This file is automatically generated. Use 'arc liberate' to rebuild it.
* @generated
* @phutil-library-version 2
*/
phutil_register_library_map(array(
'__library_version__' => 2,
'class' =>
array(
'PebbleCpplintLinter' => 'cpplint/PebbleCpplintLinter.php',
'PebbleCppcheckLinter' => 'cppcheck/PebbleCppcheckLinter.php',
),
'function' =>
array(
),
'xmap' =>
array(
'PebbleCpplintLinter' => 'ArcanistExternalLinter',
'PebbleCppcheckLinter' => 'ArcanistExternalLinter',
),
));

View file

@ -0,0 +1,134 @@
<?php
// Copyright 2024 Google LLC
//
// 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.
/**
* Uses Cppcheck to do basic checks in a C++ file.
*/
final class PebbleCppcheckLinter extends ArcanistExternalLinter {
public function getInfoName() {
return 'Cppcheck-pebble';
}
public function getInfoURI() {
return 'http://cppcheck.sourceforge.net';
}
public function getInfoDescription() {
return pht('Use `cppcheck` to perform static analysis on C/C++ code.');
}
public function getLinterName() {
return 'cppcheck-pebble';
}
public function getLinterConfigurationName() {
return 'cppcheck-pebble';
}
public function getDefaultBinary() {
return 'cppcheck';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^Cppcheck (?P<version>\d+\.\d+)$/';
if (preg_match($regex, $stdout, $matches)) {
return $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install Cppcheck using `apt-get install cppcheck` for Ubuntu'.
' or `brew install cppcheck` for Mac OS X');
}
protected function getMandatoryFlags() {
return array(
'--quiet',
'--inline-suppr',
'--xml',
'--xml-version=2',
);
}
protected function getDefaultFlags() {
return array('-j2',
'--enable=performance,style,portability,information',
'--library=tools/arc/linting/tintin.cfg,std',
'--rule-file=tools/arc/linting/tintin.rule',
'--enable=all',
'--suppress=passedByValue',
'--suppress=selfAssignment',
'--suppress=toomanyconfigs',
'--suppress=uninitStructMember',
'--suppress=unnecessaryForwardDeclaration',
'--suppress=unusedFunction',
'--suppress=variableScope',
'--suppress=unusedStructMember',
'--suppress=varFuncNullUB',
'--suppress=ConfigurationNotChecked');
}
protected function getDefaultMessageSeverity($code) {
return ArcanistLintSeverity::SEVERITY_WARNING;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$dom = new DOMDocument();
$ok = @$dom->loadXML($stderr);
if (!$ok) {
return false;
}
$errors = $dom->getElementsByTagName('error');
$messages = array();
foreach ($errors as $error) {
foreach ($error->getElementsByTagName('location') as $location) {
$message = new ArcanistLintMessage();
$message->setPath($location->getAttribute('file'));
$message->setLine($location->getAttribute('line'));
$message->setCode($error->getAttribute('id'));
$message->setName($error->getAttribute('id'));
$message->setDescription($error->getAttribute('msg'));
$message->setSeverity($this->getLintMessageSeverity($error->getAttribute('id')));
$messages[] = $message;
}
}
return $messages;
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('@^[a-z_]+$@', $code)) {
throw new Exception(
pht(
'Unrecognized severity code "%s". Expected a valid cppcheck '.
'severity code like "%s" or "%s".',
$code,
'unreadVariable',
'memleak'));
}
return $code;
}
}

View file

@ -0,0 +1,105 @@
<?php
// Copyright 2024 Google LLC
//
// 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.
/**
* Uses Google's `cpplint.py` to check code.
*/
final class PebbleCpplintLinter extends ArcanistExternalLinter {
public function getLinterName() {
return 'cpplint-pebble';
}
public function getLinterConfigurationName() {
return 'cpplint-pebble';
}
public function getDefaultBinary() {
return "tools/arc/linting/linters/cpplint/cpplint.py";
}
public function getInstallInstructions() {
return pht('Ask Tyler Hoffman to fix it.');
}
public function shouldExpectCommandErrors() {
return true;
}
public function supportsReadDataFromStdin() {
return true;
}
public function getReadDataFromStdinFilename() {
return '-';
}
protected function getDefaultFlags() {
return array();
}
protected function getDefaultMessageSeverity($code) {
return ArcanistLintSeverity::SEVERITY_WARNING;
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = explode("\n", $stderr);
$messages = array();
foreach ($lines as $line) {
$line = trim($line);
$matches = null;
$regex = '/(\d+):\s*(.*)\s*\[(.*)\] \[(\d+)\]$/';
if (!preg_match($regex, $line, $matches)) {
continue;
}
foreach ($matches as $key => $match) {
$matches[$key] = trim($match);
}
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches[1]);
$message->setCode($matches[3]);
$message->setName($matches[3]);
$message->setDescription($matches[2]);
$message->setSeverity($this->getLintMessageSeverity($matches[3]));
$messages[] = $message;
}
if ($err && !$messages) {
return false;
}
return $messages;
}
protected function getLintCodeFromLinterConfigurationKey($code) {
if (!preg_match('@^[a-z_]+/[a-z_]+$@', $code)) {
throw new Exception(
pht(
'Unrecognized lint message code "%s". Expected a valid cpplint '.
'lint code like "%s" or "%s".',
$code,
'build/include_order',
'whitespace/braces'));
}
return $code;
}
}

View file

@ -0,0 +1,142 @@
#!/usr/bin/env python
# Copyright 2024 Google LLC
#
# 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.
import re
# FW linters for tintin in python!
#
# Adding a new linter is simple. Simply,
# 1) Subclass FwLinter
# 2) Define found_lint_error(self, filename, line) and return True iff an error is found on the
# line passed in
# 3) Define SEVERITY, NAME, MESSAGE as documented here:
# https://secure.phabricator.com/book/phabricator/article/arcanist_lint_script_and_regex/
class FwLinter(object):
def construct_arcanist_error_string(self, severity, name, message, filename, line_num):
return '|'.join([severity, name, message, filename, line_num])
def handle_lint_error(self, filename, line, line_num):
""" Responsible for communicating the lint error to arcanist. Today, this just involves
printing the message because 'arc lint' monitors stdout """
print self.construct_arcanist_error_string(self.SEVERITY, self.NAME, self.MESSAGE,
filename, str(line_num))
def found_lint_error(self, filename, line):
""" Given a line, returns True if a lint error is found on the line and false otherwise """
raise NotImplementedError
#
# FwLinter Subclasses
#
class TodoFixmeLinter(FwLinter):
SEVERITY = "ADVICE"
NAME = "TODO/FIXME"
MESSAGE = "TODO/FIXME Found. Just letting you know"
jira_ticket_id_regex = re.compile(r'PBL-\d+', re.IGNORECASE)
def found_lint_error(self, filename, line):
line_lowercase = line.lower()
return 'todo' in line_lowercase or 'fixme' in line_lowercase
def handle_lint_error(self, filename, line, line_num):
message = self.MESSAGE
# If we find a JIRA ticket ID in the line, add the full JIRA URL to the message
jira_matches = self.jira_ticket_id_regex.findall(line)
if jira_matches:
jira_ticket_id = jira_matches[0]
jira_base_url = 'https://pebbletechnology.atlassian.net/browse/'
jira_url = jira_base_url + jira_ticket_id
message = ' '.join([message, jira_url])
print self.construct_arcanist_error_string(self.SEVERITY, self.NAME, message, filename,
str(line_num))
class UndefinedAttributeLinter(FwLinter):
SEVERITY = "ERROR"
NAME = "Undefined Attribute"
MESSAGE = "yo, you need to include util/attributes.h if you want to PACK stuff"
attribute_inc_regex = re.compile(r'(^#include\s+[<\"]util/attributes.h[>\"])')
def __init__(self):
self.include_found = False
def found_lint_error(self, filename, line):
if self.attribute_inc_regex.findall(line) or '#define PACKED' in line:
self.include_found = True
return False
elif ' PACKED ' in line and not self.include_found:
return True
class StaticFuncFormatLinter(FwLinter):
SEVERITY = "WARNING"
NAME = "Static Function Format Error"
MESSAGE = "umm, you forgot to add 'prv_' or mark this function as 'static'"
func_proto_regex = re.compile(r'^(\w+)\W?.*\W(\w+\([a-zA-Z])')
def found_lint_error(self, filename, line):
# Ignore header files
if (filename.endswith(".h")):
return False
matches = self.func_proto_regex.findall(line)
if matches and len(matches[0]) == 2:
groups = matches[0]
func_starts_with_prv = groups[1].startswith('prv_')
func_is_static = any(x in groups[0] for x in ['static', 'T_STATIC'])
return ((func_is_static and not func_starts_with_prv) or
(func_starts_with_prv and not func_is_static))
return False
class ColorFallbackDeprecatedMacroLinter(FwLinter):
SEVERITY = "WARNING"
NAME = "COLOR_FALLBACK() Deprecated Macro"
MESSAGE = "The macro `COLOR_FALLBACK()` has been deprecated for internal firmware use. " \
"Use the equivalent `PBL_IF_COLOR_ELSE()` macro instead. Unfortunately, we can't " \
"simply remove `COLOR_FALLBACK()` from the firmware because it's exported in the SDK."
def found_lint_error(self, filename, line):
return 'COLOR_FALLBACK' in line
#
# Code to run our FW linters
#
def lint(filename):
linters = [linter() for linter in FwLinter.__subclasses__()]
with open(filename) as f:
for i, line in enumerate(f.readlines()):
line_num = i + 1
for linter in linters:
if linter.found_lint_error(filename, line):
linter.handle_lint_error(filename, line, line_num)
if __name__ == '__main__':
import sys
filename = sys.argv[1]
lint(filename)